I am trying to lock a region of a texture for editing the data and unlocking the data back. This all seems to work great in GL however, in DX11; it only seems to work if the entire texture is edited and unlocked. i have looked into the source for lockimpl, unlockImpl, _mapstagingbuffer etc... and played around with a few of the properties.. i did manage to get it to copy to a region partially by editing the:
OgreD3D11HardwarePixelBuffer : function (_mapstagingbuffer) line: 226:
Code: Select all
mLockBox.left, mLockBox.top, 0,
I also edited function (_unmapstagingbuffer) as when the data is passed back in, it again is using the main texture lock box rather than the staging buffers width and height to be passed to the main texture..
Code: Select all
....
if(flags == D3D11_MAP_READ_WRITE || flags == D3D11_MAP_READ || flags == D3D11_MAP_WRITE)
{
D3D11_BOX srcBoxDx11 = OgreImageBoxToDx11Box(mLockBox);
srcBoxDx11.front = 0;
srcBoxDx11.back = mLockBox.getDepth();
srcBoxDx11.left = 0;
srcBoxDx11.right = mLockBox.getWidth();
srcBoxDx11.top = 0;
srcBoxDx11.bottom = mLockBox.getHeight();
....
oh, and here's the code we are using for creating the texture, editing and reuploading. (its only a single channel image to start simple with):
.cpp
Code: Select all
void PbsMaterialsGameState::createTexture()
{
imageSize = 128;
// Create the data array that will store the image CPU side and get saved with terrain and loaded back into.
data = static_cast<Ogre::uint8*>(OGRE_MALLOC(imageSize * imageSize * sizeof(Ogre::uint8), Ogre::MEMCATEGORY_RESOURCE));
parentTex = Ogre::TextureManager::getSingletonPtr()->createManual("STPhysicsVisibility",
Ogre::ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME,
Ogre::TEX_TYPE_2D_ARRAY, imageSize, imageSize, 1, 0, Ogre::PF_L8, Ogre::TU_STATIC);
// default and initialise to white
Ogre::Box bbox(0, 0, imageSize, imageSize);
Ogre::v1::HardwarePixelBufferSharedPtr buf = parentTex->getBuffer();
Ogre::uint8* pInit = static_cast<Ogre::uint8*>(buf->lock(bbox, Ogre::v1::HardwarePixelBuffer::HBL_DISCARD).data);
memset(pInit, 255, Ogre::PixelUtil::getNumElemBytes(Ogre::PF_L8) * imageSize * imageSize);
buf->unlock();
// Get pointer to the buffer for downloading/uploading data
buffer = parentTex->getBuffer().getPointer();
// Download the data.
download();
}
void PbsMaterialsGameState::destroyTexture()
{
Ogre::TextureManager::getSingletonPtr()->remove(parentTex);
parentTex.setNull();
}
void PbsMaterialsGameState::download()
{
Ogre::uint8* pDst = data;
// Download data
Ogre::Image::Box box(0, 0, imageSize, imageSize);
Ogre::uint8* pSrc = static_cast<Ogre::uint8*>(buffer->lock(box, Ogre::v1::HardwareBuffer::HBL_READ_ONLY).data);
size_t srcInc = Ogre::PixelUtil::getNumElemBytes(buffer->getFormat());
for (size_t y = box.top; y < box.bottom; ++y)
{
for (size_t x = box.left; x < box.right; ++x)
{
*pDst++ = static_cast<Ogre::uint8>(*pSrc);
pSrc += srcInc;
}
}
buffer->unlock();
}
void PbsMaterialsGameState::dirty()
{
Ogre::Rect rect;
rect.top = 0; rect.bottom = imageSize;
rect.left = 0; rect.right = imageSize;
dirtyRect(rect);
}
void PbsMaterialsGameState::dirtyRect(const Ogre::Rect& rect)
{
//if (mDirty)
//{
// mDirtyBox.left = std::min(mDirtyBox.left, static_cast<Ogre::uint32>(rect.left));
// mDirtyBox.top = std::min(mDirtyBox.top, static_cast<Ogre::uint32>(rect.top));
// mDirtyBox.right = std::max(mDirtyBox.right, static_cast<Ogre::uint32>(rect.right));
// mDirtyBox.bottom = std::max(mDirtyBox.bottom, static_cast<Ogre::uint32>(rect.bottom));
//}
//else{
mDirtyBox.left = static_cast<Ogre::uint32>(rect.left);
mDirtyBox.right = static_cast<Ogre::uint32>(rect.right);
mDirtyBox.top = static_cast<Ogre::uint32>(rect.top);
mDirtyBox.bottom = static_cast<Ogre::uint32>(rect.bottom);
mDirty = true;
//}
}
void PbsMaterialsGameState::upload()
{
if (mDirtyBox.right > imageSize){ mDirtyBox.right = imageSize; }
if (mDirtyBox.bottom > imageSize){ mDirtyBox.bottom = imageSize; }
if (mDirtyBox.top < 0){ mDirtyBox.top = 0; }
if (mDirtyBox.left < 0){ mDirtyBox.left = 0; }
// Only reupload the data if this is dirty
if (data && mDirty){
Ogre::uint8* pDstBase = static_cast<Ogre::uint8*>(buffer->lock(mDirtyBox, Ogre::v1::HardwarePixelBuffer::HBL_NORMAL).data);
size_t dstInc = Ogre::PixelUtil::getNumElemBytes(buffer->getFormat());
for (size_t y = 0; y < mDirtyBox.getHeight(); ++y)
{
Ogre::uint8* pDst = pDstBase + y * mDirtyBox.getWidth() * dstInc;
for (size_t x = 0; x < mDirtyBox.getWidth(); ++x)
{
*pDst = 0;
pDst += dstInc;
}
}
buffer->unlock();
mDirty = false;
}
}
Code: Select all
size_t terrainIdx;
size_t imageSize;
void createTexture();
void destroyTexture();
Ogre::TexturePtr parentTex;
Ogre::uint8* data;
Ogre::v1::HardwarePixelBuffer* buffer; // References the main texture buffer
void dirty();
void dirtyRect(const Ogre::Rect& rect);
Ogre::Box mDirtyBox;
Ogre::uint8* getData(){ return data; };
void freeResources();
size_t getSize(){ return imageSize; }
Ogre::TexturePtr getTexture(){ return parentTex; }
void download();
void upload();
bool mDirty;
and then passed this as the diffuse texture into the plane's diffuse block. Also changed the UV of the plane to 1:1
Code: Select all
createTexture();
Ogre::TexturePtr temptex = parentTex;
Ogre::v1::MeshPtr planeMeshV1 = Ogre::v1::MeshManager::getSingleton().createPlane( "Plane v1",
Ogre::ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME,
Ogre::Plane( Ogre::Vector3::UNIT_Y, 1.0f ), 50.0f, 50.0f,
1, 1, true, 1, 1.0f, 1.0f, Ogre::Vector3::UNIT_Z,
Ogre::v1::HardwareBuffer::HBU_STATIC,
Ogre::v1::HardwareBuffer::HBU_STATIC );
Ogre::MeshPtr planeMesh = Ogre::MeshManager::getSingleton().createManual(
"Plane", Ogre::ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME );
planeMesh->importV1( planeMeshV1.get(), true, true, true );
{
Ogre::Item *item = sceneManager->createItem( planeMesh, Ogre::SCENE_DYNAMIC );
item->setDatablock( "Marble" );
Ogre::SceneNode *sceneNode = sceneManager->getRootSceneNode( Ogre::SCENE_DYNAMIC )->
createChildSceneNode( Ogre::SCENE_DYNAMIC );
sceneNode->setPosition( 0, -1, 0 );
sceneNode->attachObject( item );
//Change the addressing mode of the roughness map to wrap via code.
//Detail maps default to wrap, but the rest to clamp.
assert( dynamic_cast<Ogre::HlmsPbsDatablock*>( item->getSubItem(0)->getDatablock() ) );
Ogre::HlmsPbsDatablock *datablock = static_cast<Ogre::HlmsPbsDatablock*>( item->getSubItem(0)->getDatablock() );
//Make a hard copy of the sampler block
Ogre::HlmsSamplerblock samplerblock;
samplerblock.mU = Ogre::TAM_WRAP;
samplerblock.mV = Ogre::TAM_WRAP;
samplerblock.mW = Ogre::TAM_WRAP;
datablock->setTexture(Ogre::PBSM_DIFFUSE, 0, temptex, &samplerblock);
}
Code: Select all
else if( arg.keysym.sym == SDLK_3 )
{
// Make all black,
dirty();
upload();
}
else if (arg.keysym.sym == SDLK_4)
{
// Dirty a region of the texture
Ogre::Rect rect(10, 10, 30, 30);
dirtyRect(rect);
upload();
}else if (arg.keysym.sym == SDLK_5)
{
// Reset back to white
Ogre::Box bbox(0, 0, imageSize, imageSize);
Ogre::v1::HardwarePixelBufferSharedPtr buf = parentTex->getBuffer();
Ogre::uint8* pInit = static_cast<Ogre::uint8*>(buf->lock(bbox, Ogre::v1::HardwarePixelBuffer::HBL_DISCARD).data);
memset(pInit, 255, Ogre::PixelUtil::getNumElemBytes(Ogre::PF_L8) * imageSize * imageSize);
buf->unlock();
}
Key 4 - This edits a region within the texture to black and uploads
Key 5 - This clears the texture back to white again for testing Key 3 & 4
In openGl, it produces this when key 4 is pressed which is the region 10,10 -> 30,30 of a 128 image:
but DX11 will not show any changes unless the code above it used, but again it doesnt work properly..
is this perhaps a bug...
i personally don't want to break these functions as they seem intrinsicly linked with creating texture arrays....
Thanks for you time and your help and look forward to one of this communities great responses
p.s. i also commented out all the spheres and boxes just to see the plane render
Also cleared the Marble material of all textures just to show the diffuse.