// Pure 32 bit float precision brute force pixel conversion; for comparison void naiveBulkPixelConversion(const PixelBox &src, const PixelBox &dst) { uint8 *srcptr = static_cast<uint8*>(src.data); uint8 *dstptr = static_cast<uint8*>(dst.data); unsigned int srcPixelSize = PixelUtil::getNumElemBytes(src.format); unsigned int dstPixelSize = PixelUtil::getNumElemBytes(dst.format); // Calculate pitches+skips in bytes int srcRowSkipBytes = src.getRowSkip()*srcPixelSize; int srcSliceSkipBytes = src.getSliceSkip()*srcPixelSize; int dstRowSkipBytes = dst.getRowSkip()*dstPixelSize; int dstSliceSkipBytes = dst.getSliceSkip()*dstPixelSize; // The brute force fallback float r,g,b,a; for(size_t z=src.front; z<src.back; z++) { for(size_t y=src.top; y<src.bottom; y++) { for(size_t x=src.left; x<src.right; x++) { PixelUtil::unpackColour(&r, &g, &b, &a, src.format, srcptr); PixelUtil::packColour(r, g, b, a, dst.format, dstptr); srcptr += srcPixelSize; dstptr += dstPixelSize; } srcptr += srcRowSkipBytes; dstptr += dstRowSkipBytes; } srcptr += srcSliceSkipBytes; dstptr += dstSliceSkipBytes; } }
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 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; }
// 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 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 pixelBox(const PixelBox& box, isab::MapPlotter* plotter) { std::vector<MC2Point> points; points.push_back(box.getTopLeft()); points.push_back(box.getTopRight()); points.push_back(box.getBottomRight()); points.push_back(box.getBottomLeft()); points.push_back(box.getTopLeft()); plotter->setPenColor(255, 0, 0); plotter->setLineWidth(3); plotter->drawPolyLine(points.begin(), points.end()); }
//----------------------------------------------------------------------------- // Util functions to convert a D3D locked box to a pixel box void D3D10HardwarePixelBuffer::fromD3DLock(PixelBox &rval, const DXGI_MAPPED_RECT &lrect) { rval.rowPitch = lrect.Pitch / PixelUtil::getNumElemBytes(rval.format); rval.slicePitch = rval.rowPitch * rval.getHeight(); assert((lrect.Pitch % PixelUtil::getNumElemBytes(rval.format))==0); rval.data = lrect.pBits; }
/// _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"); }
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); }
void ShVarItem::setCurrentValue(int key0, int key1) { if (key0 >= 0 && key1 >= 0 && data(DF_WATCHED).toBool()) { if (data(DF_DATA_PIXELBOX).value<void*>() != NULL) { PixelBox *fb = getPixelBoxPointer(); if (fb) { QVariant value; bool validValue = fb->getDataValue(key0, key1, &value); if (validValue) { setData(DF_DEBUG_SELECTED_VALUE, value.toString()); return; } } } setData(DF_DEBUG_SELECTED_VALUE, "?"); return; } setData(DF_DEBUG_SELECTED_VALUE, QVariant()); }
//----------------------------------------------------------------------- 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 TextureViewGL::ReadPixels(RenderContext_Base_GL* gl, TextureBase::ReadPixelUpdateParams& params) { if (params.lock.test_and_set(std::memory_order_release)) return; PixelBox* pixels = params.box; gl->ActivateTexture(target, texture); Size dim = gl->GetTextureParams(target); pixels->data = static_cast<uint8*>( NEX_ALLOC(dim.dx * dim.dy * pixelFormat.pixelSize, MEMCAT_GENERAL)); pixels->left = 0; pixels->right = dim.dx; pixels->top = 0; pixels->bottom = dim.dy; pixels->front = 0; pixels->back = 1; pixels->format = pixelFormat.textureFormat; pixels->deleteData = true; gl->GetTextureData(target, pixelFormat.internalFormat, pixelFormat.dataType, pixels->data); pixels->CalculatePitches(); }
/// _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 NearestSampler(PixelBox& dest, const PixelBox& src) { size_t bytesPerPix = BytesPerPixel(src.format); NEX_ASSERT(bytesPerPix == BytesPerPixel(dest.format)); float dstep = ((float) src.GetDepth() / (float) dest.GetDepth()) * .5f; float hstep = ((float) src.GetHeight() / (float) dest.GetHeight()) * .5f; float wstep = ((float) src.GetWidth() / (float) dest.GetWidth()) * .5f; for (uint32 d = dest.front; d < dest.back; ++d) { size_t doff = (uint32) (dstep * (src.slicePixelPitch * d * 2 + 1)); NEX_ASSERT(doff >= 0 && doff <= src.slicePixelPitch * d); void* destPlane = reinterpret_cast<uint8*>(dest.data) + d * dest.slicePixelPitch * bytesPerPix; for (uint32 h = dest.top; h < dest.bottom; ++h) { size_t hoff = (uint32) ((2 * h * src.rowPixelPitch + 1) * hstep); NEX_ASSERT(hoff >= 0 && hoff <= src.rowPixelPitch * h); uint8* destRow = reinterpret_cast<uint8*>(destPlane) + h * dest.rowPixelPitch * bytesPerPix; for (uint32 w = dest.left; w < dest.right; ++w) { size_t woff = (size_t) ((2 * w + 1) * wstep); NEX_ASSERT(woff >= 0 && woff <= w); uint8* srcData = reinterpret_cast<uint8*>(src.data) + (doff + hoff + woff) * bytesPerPix; // src offset uint8* destData = (destRow + w * bytesPerPix); for (uint32 j = 0; j < bytesPerPix; ++j) destData[j] = srcData[j]; } } } }
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(); }
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 }
/// _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 }
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 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(); } }
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; }
int TileBoundsCalculator::_calculateSplitY(const PixelBox& b) { double total = _sumPixels(b); double bottom = _sumPixels(b.getRowBox(b.minY)); int best = (b.maxY + b.minY) / 2; double bestSum = numeric_limits<double>::max(); double thisSlop = _slop + 1.0 / (double)(b.maxY - b.minY); if (b.getHeight() < 6) { throw HootException("The input box must be at least six pixels high."); } for (int r = b.minY + 2; r < b.maxY - 2; r++) { double rowSum = _sumPixels(b.getRowBox(r)); double rowSumMin = _sumPixels(b.getRowBox(r), _min) + _sumPixels(b.getRowBox(r + 1), _min); bottom += rowSum; double slop = abs(0.5 - bottom / total); if ((slop < thisSlop) && rowSumMin < bestSum) { best = r; bestSum = rowSumMin; } } if (bestSum == numeric_limits<double>::max()) { LOG_WARN("bestSum isn't valid. " << b.toString() << " total: " << total << " size: " << b.maxY - b.minY); } return best; }
//----------------------------------------------------------------------- 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 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; }
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 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); }