void SDLWindow::copyContentsToMemory(const PixelBox &dst, FrameBuffer buffer) { if ((dst.left < 0) || (dst.right > mWidth) || (dst.top < 0) || (dst.bottom > mHeight) || (dst.front != 0) || (dst.back != 1)) { OGRE_EXCEPT(Exception::ERR_INVALIDPARAMS, "Invalid box.", "SDLWindow::copyContentsToMemory" ); } if (buffer == FB_AUTO) { buffer = mIsFullScreen? FB_FRONT : FB_BACK; } GLenum format = Ogre::GLPixelUtil::getGLOriginFormat(dst.format); GLenum type = Ogre::GLPixelUtil::getGLOriginDataType(dst.format); if ((format == GL_NONE) || (type == 0)) { OGRE_EXCEPT(Exception::ERR_INVALIDPARAMS, "Unsupported format.", "SDLWindow::copyContentsToMemory" ); } // Switch context if different from current one RenderSystem* rsys = Root::getSingleton().getRenderSystem(); rsys->_setViewport(this->getViewport(0)); // Must change the packing to ensure no overruns! glPixelStorei(GL_PACK_ALIGNMENT, 1); glReadBuffer((buffer == FB_FRONT)? GL_FRONT : GL_BACK); glReadPixels((GLint)dst.left, (GLint)dst.top, (GLsizei)dst.getWidth(), (GLsizei)dst.getHeight(), format, type, dst.data); // restore default alignment glPixelStorei(GL_PACK_ALIGNMENT, 4); //vertical flip { size_t rowSpan = dst.getWidth() * PixelUtil::getNumElemBytes(dst.format); size_t height = dst.getHeight(); uchar *tmpData = new uchar[rowSpan * height]; uchar *srcRow = (uchar *)dst.data, *tmpRow = tmpData + (height - 1) * rowSpan; while (tmpRow >= tmpData) { memcpy(tmpRow, srcRow, rowSpan); srcRow += rowSpan; tmpRow -= rowSpan; } memcpy(dst.data, tmpData, rowSpan * height); delete [] tmpData; } }
//-------------------------------------------------------------------------------------------------// void OSXWindow::copyContentsToMemory(const PixelBox &dst, FrameBuffer buffer) { if ((dst.left < 0) || (dst.right > mWidth) || (dst.top < 0) || (dst.bottom > mHeight) || (dst.front != 0) || (dst.back != 1)) { OGRE_EXCEPT(Exception::ERR_INVALIDPARAMS, "Invalid box.", "OSXWindow::copyContentsToMemory" ); } if (buffer == FB_AUTO) { buffer = mIsFullScreen? FB_FRONT : FB_BACK; } GLenum format = Ogre::GLPixelUtil::getGLOriginFormat(dst.format); GLenum type = Ogre::GLPixelUtil::getGLOriginDataType(dst.format); if ((format == GL_NONE) || (type == 0)) { OGRE_EXCEPT(Exception::ERR_INVALIDPARAMS, "Unsupported format.", "OSXWindow::copyContentsToMemory" ); } if((dst.getWidth()*Ogre::PixelUtil::getNumElemBytes(dst.format)) & 3) { // Standard alignment of 4 is not right glPixelStorei(GL_PACK_ALIGNMENT, 1); } glReadBuffer((buffer == FB_FRONT)? GL_FRONT : GL_BACK); glReadPixels((GLint)dst.left, (GLint)dst.top, (GLsizei)dst.getWidth(), (GLsizei)dst.getHeight(), format, type, dst.data); glPixelStorei(GL_PACK_ALIGNMENT, 4); //vertical flip { size_t rowSpan = dst.getWidth() * PixelUtil::getNumElemBytes(dst.format); size_t height = dst.getHeight(); uchar *tmpData = new uchar[rowSpan * height]; uchar *srcRow = (uchar *)dst.data, *tmpRow = tmpData + (height - 1) * rowSpan; while (tmpRow >= tmpData) { memcpy(tmpRow, srcRow, rowSpan); srcRow += rowSpan; tmpRow -= rowSpan; } memcpy(dst.data, tmpData, rowSpan * height); delete [] tmpData; } }
//----------------------------------------------------------------------- void ILUtil::toOgre(const PixelBox &dst) { if(!dst.isConsecutive()) OGRE_EXCEPT( Exception::ERR_NOT_IMPLEMENTED, "Destination must currently be consecutive", "ILUtil::ilToOgre" ) ; if(dst.getWidth() != static_cast<size_t>(ilGetInteger( IL_IMAGE_WIDTH )) || dst.getHeight() != static_cast<size_t>(ilGetInteger( IL_IMAGE_HEIGHT )) || dst.getDepth() != static_cast<size_t>(ilGetInteger( IL_IMAGE_DEPTH ))) OGRE_EXCEPT( Exception::ERR_INVALIDPARAMS, "Destination dimensions must equal IL dimension", "ILUtil::ilToOgre" ) ; int ilfmt = ilGetInteger( IL_IMAGE_FORMAT ); int iltp = ilGetInteger( IL_IMAGE_TYPE ); // Check if in-memory format just matches // If yes, we can just copy it and save conversion ILFormat ifmt = OgreFormat2ilFormat( dst.format ); if(ifmt.format == ilfmt && ILabs(ifmt.type) == ILabs(iltp)) { memcpy(dst.data, ilGetData(), ilGetInteger( IL_IMAGE_SIZE_OF_DATA )); return; } // Try if buffer is in a known OGRE format so we can use OGRE its // conversion routines PixelFormat bufFmt = ilFormat2OgreFormat((int)ilfmt, (int)iltp); ifmt = OgreFormat2ilFormat( bufFmt ); if(ifmt.format == ilfmt && ILabs(ifmt.type) == ILabs(iltp)) { // IL format matches another OGRE format PixelBox src(dst.getWidth(), dst.getHeight(), dst.getDepth(), bufFmt, ilGetData()); PixelUtil::bulkPixelConversion(src, dst); return; } // Thee extremely slow method if(iltp == IL_UNSIGNED_BYTE || iltp == IL_BYTE) { ilToOgreInternal(static_cast<uint8*>(dst.data), dst.format, (uint8)0x00,(uint8)0x00,(uint8)0x00,(uint8)0xFF); } else if(iltp == IL_FLOAT) { ilToOgreInternal(static_cast<uint8*>(dst.data), dst.format, 0.0f,0.0f,0.0f,1.0f); } else if(iltp == IL_SHORT || iltp == IL_UNSIGNED_SHORT) { ilToOgreInternal(static_cast<uint8*>(dst.data), dst.format, (uint16)0x0000,(uint16)0x0000,(uint16)0x0000,(uint16)0xFFFF); } else { OGRE_EXCEPT( Exception::ERR_NOT_IMPLEMENTED, "Cannot convert this DevIL type", "ILUtil::ilToOgre" ) ; } }
void EGLWindow::copyContentsToMemory(const PixelBox &dst, FrameBuffer buffer) { if ((dst.left < 0) || (dst.right > mWidth) || (dst.top < 0) || (dst.bottom > mHeight) || (dst.front != 0) || (dst.back != 1)) { OGRE_EXCEPT(Exception::ERR_INVALIDPARAMS, "Invalid box.", "Win32Window::copyContentsToMemory" ); } if (buffer == FB_AUTO) { buffer = mIsFullScreen? FB_FRONT : FB_BACK; } GLenum format = GLESPixelUtil::getGLOriginFormat(dst.format); GLenum type = GLESPixelUtil::getGLOriginDataType(dst.format); if ((format == 0) || (type == 0)) { OGRE_EXCEPT(Exception::ERR_INVALIDPARAMS, "Unsupported format.", "GtkEGLWindow::copyContentsToMemory" ); } // Switch context if different from current one RenderSystem* rsys = Root::getSingleton().getRenderSystem(); rsys->_setViewport(this->getViewport(0)); #if OGRE_NO_GLES3_SUPPORT == 0 if(dst.getWidth() != dst.rowPitch) glPixelStorei(GL_PACK_ROW_LENGTH, dst.rowPitch); #endif // Must change the packing to ensure no overruns! glPixelStorei(GL_PACK_ALIGNMENT, 1); //glReadBuffer((buffer == FB_FRONT)? GL_FRONT : GL_BACK); glReadPixels((GLint)0, (GLint)(mHeight - dst.getHeight()), (GLsizei)dst.getWidth(), (GLsizei)dst.getHeight(), format, type, dst.getTopLeftFrontPixelPtr()); // restore default alignment glPixelStorei(GL_PACK_ALIGNMENT, 4); #if OGRE_NO_GLES3_SUPPORT == 0 glPixelStorei(GL_PACK_ROW_LENGTH, 0); #endif PixelUtil::bulkPixelVerticalFlip(dst); }
void SDLWindow::copyContentsToMemory(const PixelBox &dst, FrameBuffer buffer) { if (dst.getWidth() > mWidth || dst.getHeight() > mHeight || dst.front != 0 || dst.back != 1) { OGRE_EXCEPT(Exception::ERR_INVALIDPARAMS, "Invalid box.", "SDLWindow::copyContentsToMemory" ); } if (buffer == FB_AUTO) { buffer = mIsFullScreen? FB_FRONT : FB_BACK; } GLenum format = Ogre::GL3PlusPixelUtil::getGLOriginFormat(dst.format); GLenum type = Ogre::GL3PlusPixelUtil::getGLOriginDataType(dst.format); if ((format == GL_NONE) || (type == 0)) { OGRE_EXCEPT(Exception::ERR_INVALIDPARAMS, "Unsupported format.", "SDLWindow::copyContentsToMemory" ); } if(dst.getWidth() != dst.rowPitch) { glPixelStorei(GL_PACK_ROW_LENGTH, dst.rowPitch); } if((dst.getWidth()*Ogre::PixelUtil::getNumElemBytes(dst.format)) & 3) { // Standard alignment of 4 is not right glPixelStorei(GL_PACK_ALIGNMENT, 1); } glReadBuffer((buffer == FB_FRONT)? GL_FRONT : GL_BACK); glReadPixels((GLint)0, (GLint)(mHeight - dst.getHeight()), (GLsizei)dst.getWidth(), (GLsizei)dst.getHeight(), format, type, dst.getTopLeftFrontPixelPtr()); glPixelStorei(GL_PACK_ALIGNMENT, 4); glPixelStorei(GL_PACK_ROW_LENGTH, 0); PixelUtil::bulkPixelVerticalFlip(dst); }
void GLES2HardwarePixelBuffer::blitFromMemory(const PixelBox &src, const Image::Box &dstBox) { if (!mBuffer.contains(dstBox)) { OGRE_EXCEPT(Exception::ERR_INVALIDPARAMS, "Destination box out of range", "GLES2HardwarePixelBuffer::blitFromMemory"); } PixelBox scaled; if (src.getWidth() != dstBox.getWidth() || src.getHeight() != dstBox.getHeight() || src.getDepth() != dstBox.getDepth()) { // Scale to destination size. // This also does pixel format conversion if needed allocateBuffer(); scaled = mBuffer.getSubVolume(dstBox); Image::scale(src, scaled, Image::FILTER_BILINEAR); } #if OGRE_PLATFORM != OGRE_PLATFORM_APPLE_IOS else if ((src.format != mFormat) || ((GLES2PixelUtil::getGLOriginFormat(src.format) == 0) && (src.format != PF_R8G8B8))) #else else if (GLES2PixelUtil::getGLOriginFormat(src.format) == 0) #endif { // Extents match, but format is not accepted as valid source format for GL // do conversion in temporary buffer allocateBuffer(); scaled = mBuffer.getSubVolume(dstBox); PixelUtil::bulkPixelConversion(src, scaled); } else { allocateBuffer(); // No scaling or conversion needed scaled = src; if (src.format == PF_R8G8B8) { scaled.format = PF_B8G8R8; PixelUtil::bulkPixelConversion(src, scaled); } #if OGRE_PLATFORM == OGRE_PLATFORM_NACL if (src.format == PF_A8R8G8B8) { scaled.format = PF_A8B8G8R8; PixelUtil::bulkPixelConversion(src, scaled); } #endif } upload(scaled, dstBox); freeBuffer(); }
// Convert Ogre pixelbox extent to D3D rectangle RECT toD3DRECTExtent(const PixelBox &lockBox) { RECT prect; assert(lockBox.getDepth() == 1); prect.left = 0; prect.right = static_cast<LONG>(lockBox.getWidth()); prect.top = 0; prect.bottom = static_cast<LONG>(lockBox.getHeight()); return prect; }
void GLESHardwarePixelBuffer::blitToMemory(const Image::Box &srcBox, const PixelBox &dst) { if (!mBuffer.contains(srcBox)) { OGRE_EXCEPT(Exception::ERR_INVALIDPARAMS, "source box out of range", "GLESHardwarePixelBuffer::blitToMemory"); } if (srcBox.left == 0 && srcBox.right == getWidth() && srcBox.top == 0 && srcBox.bottom == getHeight() && srcBox.front == 0 && srcBox.back == getDepth() && dst.getWidth() == getWidth() && dst.getHeight() == getHeight() && dst.getDepth() == getDepth() && GLESPixelUtil::getGLOriginFormat(dst.format) != 0) { // The direct case: the user wants the entire texture in a format supported by GL // so we don't need an intermediate buffer download(dst); } else { // Use buffer for intermediate copy allocateBuffer(); // Download entire buffer download(mBuffer); if(srcBox.getWidth() != dst.getWidth() || srcBox.getHeight() != dst.getHeight() || srcBox.getDepth() != dst.getDepth()) { // We need scaling Image::scale(mBuffer.getSubVolume(srcBox), dst, Image::FILTER_BILINEAR); } else { // Just copy the bit that we need PixelUtil::bulkPixelConversion(mBuffer.getSubVolume(srcBox), dst); } freeBuffer(); } }
// Convert Ogre pixelbox extent to D3D box D3DBOX toD3DBOXExtent(const PixelBox &lockBox) { D3DBOX pbox; pbox.Left = 0; pbox.Right = static_cast<UINT>(lockBox.getWidth()); pbox.Top = 0; pbox.Bottom = static_cast<UINT>(lockBox.getHeight()); pbox.Front = 0; pbox.Back = static_cast<UINT>(lockBox.getDepth()); return pbox; }
//----------------------------------------------------------------------------- void D3D11HardwarePixelBuffer::blitToMemory(const Image::Box &srcBox, const PixelBox &dst) { // Decide on pixel format of temp surface PixelFormat tmpFormat = mFormat; if(D3D11Mappings::_getPF(dst.format) != DXGI_FORMAT_UNKNOWN) { tmpFormat = dst.format; } assert(srcBox.getDepth() == 1 && dst.getDepth() == 1); //This is a pointer to the texture we're trying to copy //Only implemented for 2D at the moment... ID3D11Texture2D *textureResource = mParentTexture->GetTex2D(); // get the description of the texture D3D11_TEXTURE2D_DESC desc = {0}; textureResource->GetDesc( &desc ); //Alter the description to set up a staging texture desc.Usage = D3D11_USAGE_STAGING; //This texture is not bound to any part of the pipeline desc.BindFlags = 0; //Allow CPU Access desc.CPUAccessFlags = D3D11_CPU_ACCESS_READ; //No Misc Flags desc.MiscFlags = 0; //Create the staging texture ID3D11Texture2D* pStagingTexture = NULL; mDevice->CreateTexture2D( &desc, NULL, &pStagingTexture ); //Copy our texture into the staging texture mDevice.GetImmediateContext()->CopyResource( pStagingTexture, textureResource ); //Create a mapped resource and map the staging texture to the resource D3D11_MAPPED_SUBRESOURCE mapped = {0}; mDevice.GetImmediateContext()->Map( pStagingTexture, 0, D3D11_MAP_READ , 0, &mapped ); // read the data out of the texture. unsigned int rPitch = mapped.RowPitch; BYTE *data = ((BYTE *)mapped.pData); //Using existing OGRE functions DXGI_MAPPED_RECT lrect; lrect.pBits = data; lrect.Pitch = rPitch; PixelBox locked(dst.getWidth(), dst.getHeight(), dst.getDepth(), tmpFormat); fromD3DLock(locked, lrect); PixelUtil::bulkPixelConversion(locked, dst); //Release the staging texture mDevice.GetImmediateContext()->Unmap( pStagingTexture, 0 ); pStagingTexture->Release(); }
void fromD3DLock(PixelBox &rval, const D3DLOCKED_BOX &lbox) { size_t bpp = PixelUtil::getNumElemBytes(rval.format); if (bpp != 0) { rval.rowPitch = lbox.RowPitch / bpp; rval.slicePitch = lbox.SlicePitch / bpp; assert((lbox.RowPitch % bpp)==0); assert((lbox.SlicePitch % bpp)==0); } else if (PixelUtil::isCompressed(rval.format)) { rval.rowPitch = rval.getWidth(); rval.slicePitch = rval.getWidth() * rval.getHeight(); } else { OGRE_EXCEPT(Exception::ERR_INVALIDPARAMS, "Invalid pixel format", "fromD3DLock"); } rval.data = lbox.pBits; }
//----------------------------------------------------------------------------- void GLES2TextureBuffer::download(const PixelBox &data) { #if 0 || defined(GL_NV_get_tex_image) if(data.getWidth() != getWidth() || data.getHeight() != getHeight() || data.getDepth() != getDepth()) OGRE_EXCEPT(Exception::ERR_INVALIDPARAMS, "only download of entire buffer is supported by GL", "GLTextureBuffer::download"); glBindTexture( mTarget, mTextureID ); if(PixelUtil::isCompressed(data.format)) { if(data.format != mFormat || !data.isConsecutive()) OGRE_EXCEPT(Exception::ERR_INVALIDPARAMS, "Compressed images must be consecutive, in the source format", "GLTextureBuffer::download"); // Data must be consecutive and at beginning of buffer as PixelStorei not allowed // for compressed formate glGetCompressedTexImageNV(mFaceTarget, mLevel, data.data); } else { if((data.getWidth()*PixelUtil::getNumElemBytes(data.format)) & 3) { // Standard alignment of 4 is not right glPixelStorei(GL_PACK_ALIGNMENT, 1); } // We can only get the entire texture glGetTexImageNV(mFaceTarget, mLevel, GLES2PixelUtil::getGLOriginFormat(data.format), GLES2PixelUtil::getGLOriginDataType(data.format), data.data); // Restore defaults glPixelStorei(GL_PACK_ALIGNMENT, 4); } #else OGRE_EXCEPT(Exception::ERR_NOT_IMPLEMENTED, "Downloading texture buffers is not supported by OpenGL ES", "GLES2TextureBuffer::download"); #endif }
void EGLWindow::copyContentsToMemory(const Box& src, const PixelBox &dst, FrameBuffer buffer) { if(src.right > mWidth || src.bottom > mHeight || src.front != 0 || src.back != 1 || dst.getWidth() != src.getWidth() || dst.getHeight() != src.getHeight() || dst.getDepth() != 1) { OGRE_EXCEPT(Exception::ERR_INVALIDPARAMS, "Invalid box.", "EGLWindow::copyContentsToMemory"); } if (buffer == FB_AUTO) { buffer = mIsFullScreen? FB_FRONT : FB_BACK; } static_cast<GLRenderSystemCommon*>(Root::getSingleton().getRenderSystem()) ->_copyContentsToMemory(getViewport(0), src, dst, buffer); }
/// _Tool_ tex .......................... // (remove alpha channel for ter tex prv img) void App::ToolTexAlpha() { Ogre::Image im; im.load("jungle_5d.png", "General"); PixelBox pb = im.getPixelBox(); int w = pb.getWidth(), h = pb.getHeight(); for(int j=0; j < h; ++j) for(int i=0; i < w; ++i) { ColourValue c = pb.getColourAt(i,j,0); c.a = 1.f; pb.setColourAt(c,i,j,0); } im.save(PATHMANAGER::Data()+"/prv.png"); }
/// _Tool_ tex .......................... // (split 1 rgba terrain texture to 2, 1st rgb and 2nd with alpha in red) void CGui::ToolTexAlpha() { strlist li; string data = PATHMANAGER::Data()+"/terrain"; PATHMANAGER::DirList(data, li); //PATHMANAGER::DirList(data+"2", li); int ii=0; for (strlist::iterator i = li.begin(); i != li.end(); ++i,++ii) if (/*ii < 3 &&*/ !StringUtil::match(*i, "*.txt", false)) { String n = *i; Image im; im.load(n, "General"); PixelBox pb = im.getPixelBox(); //pb.setConsecutive(); int w = pb.getWidth(), h = pb.getHeight(); uchar* rgb = new uchar[w*h*3]; uchar* aa = new uchar[w*h]; register int i,j,a=0,b=0; for (j=0; j < h; ++j) for (i=0; i < w; ++i) { //pb.data ColourValue c = pb.getColourAt(i,j,0); rgb[a++] = c.b * 255.f; rgb[a++] = c.g * 255.f; rgb[a++] = c.r * 255.f; aa[b++] = c.a * 255.f; } Ogre::Image ic,ia; ic.loadDynamicImage(rgb, w,h, PF_R8G8B8); ic.save(PATHMANAGER::Data()+"/"+n+"_d.png"); ia.loadDynamicImage(aa, w,h, PF_L8); ia.save(PATHMANAGER::Data()+"/"+n+"_s.png"); delete[]rgb; delete[]aa; } }
void GL3PlusHardwarePixelBuffer::blitFromMemory(const PixelBox &src, const Image::Box &dstBox) { if (!mBuffer.contains(dstBox)) { OGRE_EXCEPT(Exception::ERR_INVALIDPARAMS, "Destination box out of range", "GL3PlusHardwarePixelBuffer::blitFromMemory"); } PixelBox scaled; if (src.getWidth() != dstBox.getWidth() || src.getHeight() != dstBox.getHeight() || src.getDepth() != dstBox.getDepth()) { // Scale to destination size. // This also does pixel format conversion if needed. allocateBuffer( mSizeInBytes ); scaled = mBuffer.getSubVolume(dstBox); Image::scale(src, scaled, Image::FILTER_BILINEAR); } else if (GL3PlusPixelUtil::getGLOriginFormat(src.format) == 0) { // Extents match, but format is not accepted as valid // source format for GL. Do conversion in temporary buffer. allocateBuffer( mSizeInBytes ); scaled = mBuffer.getSubVolume(dstBox); PixelUtil::bulkPixelConversion(src, scaled); } else { allocateBuffer( mSizeInBytes ); // No scaling or conversion needed. scaled = src; } upload(scaled, dstBox); freeBuffer(); }
int TileBoundsCalculator::_calculateSplitX(PixelBox& b) { double total = _sumPixels(b); double left = _sumPixels(b.getColumnBox(b.minX)); int best = (b.maxX + b.minX) / 2; double bestSum = numeric_limits<double>::max(); double thisSlop = _slop + 1.0 / (double)(b.maxX - b.minX); if (b.getWidth() < 6) { throw HootException("The input box must be at least six pixels high."); } for (int c = b.minX + 2; c < b.maxX - 2; c++) { double colSum = _sumPixels(b.getColumnBox(c)); double colSumMin = _sumPixels(b.getColumnBox(c), _min) + _sumPixels(b.getColumnBox(c + 1), _min); left += colSum; double slop = abs(0.5 - left / total); if ((slop < thisSlop) && colSumMin < bestSum) { best = c; bestSum = colSumMin; } } if (bestSum == numeric_limits<double>::max()) { LOG_WARN("bestSum isn't valid. " << b.toString()); } return best; }
/// _Tool_ brushes prv ...................................................... // update all Brushes png void CGui::ToolBrushesPrv() { Image im; for (int i=0; i < app->brSetsNum; ++i) { app->SetBrushPreset(i); app->brushPrvTex->convertToImage(im); im.save("data/editor/brush"+toStr(i)+".png"); // todo: ?brush presets in xml, auto upd prvs- } #if 1 ///---- combine all images into one ---- const int ii = 86; Image ir; ir.load("brushes-e.png","General"); for (int i=0; i <= ii; ++i) { String s = "brush" + toStr(i) + ".png"; im.load(s,"General"); PixelBox pb = im.getPixelBox(); int xx = pb.getWidth(), yy = pb.getHeight(); //void * pb.data int a = (i%16)*128, b = (i/16)*128; register int x,y; ColourValue c; for (y = 0; y < yy; ++y) for (x = 0; x < xx; ++x) { c = im.getColourAt(x,y,0); ir.setColourAt(c,a+x,b+y,0); } } ir.save("brushes.png"); #endif }
//----------------------------------------------------------------------------- // 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; }
void GLESTextureBuffer::upload(const PixelBox &data, const Image::Box &dest) { glBindTexture(mTarget, mTextureID); GL_CHECK_ERROR; if (PixelUtil::isCompressed(data.format)) { if(data.format != mFormat || !data.isConsecutive()) OGRE_EXCEPT(Exception::ERR_INVALIDPARAMS, "Compressed images must be consecutive, in the source format", "GLESTextureBuffer::upload"); GLenum format = GLESPixelUtil::getClosestGLInternalFormat(mFormat); // Data must be consecutive and at beginning of buffer as PixelStorei not allowed // for compressed formats if (dest.left == 0 && dest.top == 0) { glCompressedTexImage2D(mFaceTarget, mLevel, format, dest.getWidth(), dest.getHeight(), 0, data.getConsecutiveSize(), data.data); GL_CHECK_ERROR; } else { glCompressedTexSubImage2D(mFaceTarget, mLevel, dest.left, dest.top, dest.getWidth(), dest.getHeight(), format, data.getConsecutiveSize(), data.data); GL_CHECK_ERROR; } } else if (mSoftwareMipmap) { if (data.getWidth() != data.rowPitch) { // TODO OGRE_EXCEPT(Exception::ERR_INVALIDPARAMS, "Unsupported texture format", "GLESTextureBuffer::upload"); } if (data.getHeight() * data.getWidth() != data.slicePitch) { // TODO OGRE_EXCEPT(Exception::ERR_INVALIDPARAMS, "Unsupported texture format", "GLESTextureBuffer::upload"); } glPixelStorei(GL_UNPACK_ALIGNMENT, 1); GL_CHECK_ERROR; buildMipmaps(data); } else { if(data.getWidth() != data.rowPitch) { // TODO OGRE_EXCEPT(Exception::ERR_INVALIDPARAMS, "Unsupported texture format", "GLESTextureBuffer::upload"); } if(data.getHeight()*data.getWidth() != data.slicePitch) { // TODO OGRE_EXCEPT(Exception::ERR_INVALIDPARAMS, "Unsupported texture format", "GLESTextureBuffer::upload"); } if ((data.getWidth() * PixelUtil::getNumElemBytes(data.format)) & 3) { // Standard alignment of 4 is not right glPixelStorei(GL_UNPACK_ALIGNMENT, 1); GL_CHECK_ERROR; } // LogManager::getSingleton().logMessage("GLESTextureBuffer::upload - ID: " + StringConverter::toString(mTextureID) + // " Format: " + PixelUtil::getFormatName(data.format) + // " Origin format: " + StringConverter::toString(GLESPixelUtil::getGLOriginFormat(data.format, 0, ' ', std::ios::hex)) + // " Data type: " + StringConverter::toString(GLESPixelUtil::getGLOriginDataType(data.format, 0, ' ', std::ios::hex)) // ); glTexSubImage2D(mFaceTarget, mLevel, dest.left, dest.top, dest.getWidth(), dest.getHeight(), GLESPixelUtil::getGLOriginFormat(data.format), GLESPixelUtil::getGLOriginDataType(data.format), data.data); GL_CHECK_ERROR; } glPixelStorei(GL_UNPACK_ALIGNMENT, 4); GL_CHECK_ERROR; }
//----------------------------------------------------------------------------- void GLES2TextureBuffer::download(const PixelBox &data) { if(data.getWidth() != getWidth() || data.getHeight() != getHeight() || data.getDepth() != getDepth()) OGRE_EXCEPT(Exception::ERR_INVALIDPARAMS, "only download of entire buffer is supported by GL ES", "GLES2TextureBuffer::download"); if(PixelUtil::isCompressed(data.format)) { OGRE_EXCEPT(Exception::ERR_INVALIDPARAMS, "Compressed images cannot be downloaded by GL ES", "GLES2TextureBuffer::download"); } GLenum texBinding = GL_NONE; switch (mTarget) { case GL_TEXTURE_2D: texBinding = GL_TEXTURE_BINDING_2D; break; case GL_TEXTURE_CUBE_MAP: texBinding = GL_TEXTURE_BINDING_CUBE_MAP; break; #if OGRE_NO_GLES3_SUPPORT == 0 case GL_TEXTURE_3D: texBinding = GL_TEXTURE_BINDING_3D; break; #endif default: return; } #if OGRE_NO_GLES3_SUPPORT == 0 if(data.getWidth() != data.rowPitch) OGRE_CHECK_GL_ERROR(glPixelStorei(GL_PACK_ROW_LENGTH, data.rowPitch)); if(data.getHeight()*data.getWidth() != data.slicePitch) OGRE_CHECK_GL_ERROR(glPixelStorei(GL_PACK_IMAGE_HEIGHT, (data.slicePitch/data.getWidth()))); if(data.left > 0 || data.top > 0 || data.front > 0) OGRE_CHECK_GL_ERROR(glPixelStorei(GL_PACK_SKIP_PIXELS, data.left + data.rowPitch * data.top + data.slicePitch * data.front)); #endif if((data.getWidth()*PixelUtil::getNumElemBytes(data.format)) & 3) { // Standard alignment of 4 is not right OGRE_CHECK_GL_ERROR(glPixelStorei(GL_PACK_ALIGNMENT, 1)); } GLint currentFBO = 0; GLuint tempFBO = 0; OGRE_CHECK_GL_ERROR(glGetIntegerv(GL_FRAMEBUFFER_BINDING, ¤tFBO)); OGRE_CHECK_GL_ERROR(glGenFramebuffers(1, &tempFBO)); OGRE_CHECK_GL_ERROR(glBindFramebuffer(GL_FRAMEBUFFER, tempFBO)); switch (mTarget) { case GL_TEXTURE_2D: case GL_TEXTURE_CUBE_MAP: OGRE_CHECK_GL_ERROR(glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, mTextureID, 0)); OGRE_CHECK_GL_ERROR(glCheckFramebufferStatus(GL_FRAMEBUFFER)); OGRE_CHECK_GL_ERROR(glReadPixels(0, 0, data.getWidth(), data.getHeight(), GLES2PixelUtil::getGLOriginFormat(data.format), GLES2PixelUtil::getGLOriginDataType(data.format), data.data)); break; #if OGRE_NO_GLES3_SUPPORT == 0 case GL_TEXTURE_3D: for (int i = 0; i < desc.depth; i++) { OGRE_CHECK_GL_ERROR(glFramebufferTexture3D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_3D, mTextureID, mLevel, i)); OGRE_CHECK_GL_ERROR(glReadPixels(0, 0, data.getWidth(), data.getHeight(), GL_RGBA, GL_UNSIGNED_BYTE, pixels + 4 * i * data.getWidth() * data.getHeight())); } break; #endif } // Restore defaults #if OGRE_NO_GLES3_SUPPORT == 0 OGRE_CHECK_GL_ERROR(glPixelStorei(GL_PACK_ROW_LENGTH, 0)); OGRE_CHECK_GL_ERROR(glPixelStorei(GL_PACK_IMAGE_HEIGHT, 0)); OGRE_CHECK_GL_ERROR(glPixelStorei(GL_PACK_SKIP_PIXELS, 0)); #endif OGRE_CHECK_GL_ERROR(glPixelStorei(GL_PACK_ALIGNMENT, 4)); OGRE_CHECK_GL_ERROR(glBindFramebuffer(GL_FRAMEBUFFER, currentFBO)); OGRE_CHECK_GL_ERROR(glDeleteFramebuffers(1, &tempFBO)); }
//-------------------------------------------------------------------------- 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); }
//----------------------------------------------------------------------- void ILUtil::fromOgre(const PixelBox &src) { // ilTexImage http://openil.sourceforge.net/docs/il/f00059.htm ILFormat ifmt = OgreFormat2ilFormat( src.format ); if(src.isConsecutive() && ifmt.isValid()) { // The easy case, the buffer is laid out in memory just like // we want it to be and is in a format DevIL can understand directly // We could even save the copy if DevIL would let us ilTexImage(static_cast<ILuint>(src.getWidth()), static_cast<ILuint>(src.getHeight()), static_cast<ILuint>(src.getDepth()), ifmt.numberOfChannels, ifmt.format, ifmt.type, src.data); } else if(ifmt.isValid()) { // The format can be understood directly by DevIL. The only // problem is that ilTexImage expects our image data consecutively // so we cannot use that directly. // Let DevIL allocate the memory for us, and copy the data consecutively // to its memory ilTexImage(static_cast<ILuint>(src.getWidth()), static_cast<ILuint>(src.getHeight()), static_cast<ILuint>(src.getDepth()), ifmt.numberOfChannels, ifmt.format, ifmt.type, 0); PixelBox dst(src.getWidth(), src.getHeight(), src.getDepth(), src.format, ilGetData()); PixelUtil::bulkPixelConversion(src, dst); } else { // Here it gets ugly. We're stuck with a pixel format that DevIL // can't do anything with. We will do a bulk pixel conversion and // then feed it to DevIL anyway. The problem is finding the best // format to convert to. // most general format supported by OGRE and DevIL PixelFormat fmt = PixelUtil::hasAlpha(src.format)?PF_FLOAT32_RGBA:PF_FLOAT32_RGB; // Make up a pixel format // We don't have to consider luminance formats as they have // straight conversions to DevIL, just weird permutations of RGBA an LA int depths[4]; PixelUtil::getBitDepths(src.format, depths); // Native endian format with all bit depths<8 can safely and quickly be // converted to 24/32 bit if(PixelUtil::isNativeEndian(src.format) && depths[0]<=8 && depths[1]<=8 && depths[2]<=8 && depths[3]<=8) { if(PixelUtil::hasAlpha(src.format)) { fmt = PF_A8R8G8B8; } else { fmt = PF_R8G8B8; } } // Let DevIL allocate the memory for us, then do the conversion ourselves ifmt = OgreFormat2ilFormat( fmt ); ilTexImage(static_cast<ILuint>(src.getWidth()), static_cast<ILuint>(src.getHeight()), static_cast<ILuint>(src.getDepth()), ifmt.numberOfChannels, ifmt.format, ifmt.type, 0); PixelBox dst(src.getWidth(), src.getHeight(), src.getDepth(), fmt, ilGetData()); PixelUtil::bulkPixelConversion(src, dst); } }
//----------------------------------------------------------------------------- // 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 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(); } } }
//----------------------------------------------------------------------------- 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 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 }
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); } }
//----------------------------------------------------------------------- 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 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); }