fill texture3d slice wise - c++

I try to fill a texture3D slice wise with 2d images.
my result only gives me back the first of the 6 images like you can see in this picture:
to be sure that it is not a render problem like wrong uvw coordinates I also give you the picture of the uvw coordinates:
here is the code of the creation of the texture3d:
if (ETextureType::Texture3D == TextureType)
{
ID3D11Texture3D* pTexture3D = nullptr;
D3D11_TEXTURE3D_DESC TextureDesc;
ZeroMemory(&TextureDesc, sizeof(TextureDesc));
TextureDesc.Width = nWidth;
TextureDesc.Height = nHeight;
TextureDesc.MipLevels = nMipMaps;
TextureDesc.Depth = nDepth;
TextureDesc.Usage = D3D11_USAGE_DEFAULT;
TextureDesc.BindFlags = D3D11_BIND_SHADER_RESOURCE;
switch (TextureFormat)
{
case ETextureFormat::R8G8B8A8:
{
TextureDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
}
break;
case ETextureFormat::R32FG32FB32FA32F:
{
TextureDesc.Format = DXGI_FORMAT_R32G32B32A32_FLOAT;
}
break;
default:
DebugAssertOnce(UNKNOWN_TEXTURE_FORMAT);
}
HRESULT hr = m_pD3D11Device->CreateTexture3D(&TextureDesc, nullptr, &pTexture3D);
if (FAILED(hr))
{
DebugAssertOnce(UNABLE_TO_CREATE_TEXTURE);
return false;
}
if (bCreateShaderResourceView)
{
D3D11_SHADER_RESOURCE_VIEW_DESC SRVDesc;
ZeroMemory(&SRVDesc, sizeof(SRVDesc));
SRVDesc.Format = TextureDesc.Format;
SRVDesc.Texture3D.MipLevels = TextureDesc.MipLevels;
SRVDesc.Texture3D.MostDetailedMip = 0;
SRVDesc.ViewDimension = D3D11_SRV_DIMENSION_TEXTURE3D;
hr = m_pD3D11Device->CreateShaderResourceView(pTexture3D, &SRVDesc, &pShaderResourceView);
if (FAILED(hr))
{
pTexture3D->Release();
DebugAssertOnce(UNABLE_TO_CREATE_SHADER_RESOURCE_VIEW);
return false;
}
}
else if (bCreateRenderTargetView)
{
ID3D11RenderTargetView* pRenderTargetView = nullptr;
hr = m_pD3D11Device->CreateRenderTargetView(pTexture3D, nullptr, &pRenderTargetView);
if (FAILED(hr))
{
pShaderResourceView->Release();
pTexture3D->Release();
DebugAssertOnce(UNABLE_TO_CREATE_RENDERTARGET_VIEW);
return false;
}
pView = pRenderTargetView;
}
*ppTexture = new CTextureDX11(TextureType, pTexture3D, pShaderResourceView, pView);
return true;
}
and also the filling part:
bool CGraphicsDriverDX11::CreateTexture3DFromImageBuffers(CTexture** ppTexture, const std::vector<CImageBuffer*>* pvecImageBuffers)
{
uint32_t nWidth = pvecImageBuffers->front()->GetWidth();
uint32_t nHeight = pvecImageBuffers->front()->GetHeight();
uint32_t nMipMapLevels = 1;
bool bRet = CreateTexture(ppTexture, nWidth, nHeight, ETextureType::Texture3D, ETextureFormat::R8G8B8A8, nMipMapLevels, false, true, false, static_cast<UINT>(pvecImageBuffers->size()));
if (bRet)
{
ID3D11Texture3D* pD3DTexture = static_cast<ID3D11Texture3D*>((*ppTexture)->GetTexture());
for (size_t nImageBuffer = 0; nImageBuffer < pvecImageBuffers->size(); ++nImageBuffer)
{
uint32_t nIndex = D3D11CalcSubresource(static_cast<UINT>(nImageBuffer), 0, 1);
m_pD3D11DeviceContext->UpdateSubresource(pD3DTexture, nIndex, nullptr, pvecImageBuffers->at(nImageBuffer)->GetData(), nWidth * 4, 0);
}
}
return bRet;
}
I tried a lot... for example I changed this code to texture2DArray and it worked fine. so the mistake is not my CImageBuffer class. also the nDepth variable has the correct value... I think I have to use another command for UpdateSubresource or at least change the parameters somehow.
I also didn't find some examples in the internet.
Thank you in advanced

All the depth textures in a slice are side-by-side in a single subresource. You also need to compute how many depth images are present in a slice for a given miplevel.
This gives you the subresource index which contains the entire slice:
D3D11CalcSubresource(level, 0, mipLevels);
This gives you the number of images in a slice for a given miplevel:
std::max(depth >> level, 1);
Each image in the slice has a pitch of D3D11_MAPPED_SUBRESOURCE.RowPitch laid out one after another in the subresource, with the total size in bytes of the slice as D3D11_MAPPED_SUBRESOURCE.DepthPitch.
For example, here is some code from DirectXTex trimmed down a bit to make it easier to read. It is reading the data out of a captured 3D volume texture, but the logic is the same when filling out textures.
if (metadata.IsVolumemap())
{
assert(metadata.arraySize == 1);
size_t height = metadata.height;
size_t depth = metadata.depth;
for (size_t level = 0; level < metadata.mipLevels; ++level)
{
UINT dindex = D3D11CalcSubresource(level, 0, metadata.mipLevels);
D3D11_MAPPED_SUBRESOURCE mapped;
HRESULT hr = pContext->Map(pSource, dindex, D3D11_MAP_READ, 0, &mapped);
if (FAILED(hr))
// error
auto pslice = reinterpret_cast<const uint8_t*>(mapped.pData);
size_t lines = ComputeScanlines(metadata.format, height);
// For uncompressed images, lines == height
for (size_t slice = 0; slice < depth; ++slice)
{
const Image* img = result.GetImage(level, 0, slice);
const uint8_t* sptr = pslice;
uint8_t* dptr = img->pixels;
for (size_t h = 0; h < lines; ++h)
{
size_t msize = std::min<size_t>(img->rowPitch, mapped.RowPitch);
memcpy_s(dptr, img->rowPitch, sptr, msize);
sptr += mapped.RowPitch;
dptr += img->rowPitch;
}
pslice += mapped.DepthPitch;
}
pContext->Unmap(pSource, dindex);
if (height > 1)
height >>= 1;
if (depth > 1)
depth >>= 1;
}
}

Related

Rendering frames from a webcam to a DirectX 11 texture

I am having difficulty updating a DirectX 11 texture with the image data from a webcam frame buffer in memory. I've managed to create a texture from a single frame in the buffer but as the buffer is overwritten with the next frame the texture doesn't update. So I'm left with a snap shot image rather than a live stream which I'm after.
I am trying to use the Map/Unmap methods for updating an ID3D11Texture2D resource because that is supposedly more efficient than using the UpdateSubresource method. I haven't managed to get either to work. I'm new to DirectX and I just can't find a good explanation anywhere on how to accomplish this.
Create texture here:
bool CreateCamTexture(ID3D11ShaderResourceView** out_srv, RGBQUAD* ptrimg, int* image_width, int* image_height)
{
ZeroMemory(&desc, sizeof(desc));
desc.Width = *image_width;
desc.Height = *image_height;
desc.MipLevels = 1;
desc.ArraySize = 1;
desc.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
desc.SampleDesc.Count = 1;
desc.Usage = D3D11_USAGE_DYNAMIC;
desc.BindFlags = D3D11_BIND_SHADER_RESOURCE;
desc.CPUAccessFlags = D3D11_CPU_ACCESS_WRITE;
std::cout << ptrimg << std::endl;
subResource.pSysMem = ptrimg;
subResource.SysMemPitch = desc.Width * 4;
subResource.SysMemSlicePitch = 0;
g_pd3dDevice->CreateTexture2D(&desc, &subResource, &pTexture);
ZeroMemory(&srvDesc, sizeof(srvDesc));
srvDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
srvDesc.ViewDimension = D3D11_SRV_DIMENSION_TEXTURE2D;
srvDesc.Texture2D.MipLevels = desc.MipLevels;
srvDesc.Texture2D.MostDetailedMip = 0;
g_pd3dDevice->CreateShaderResourceView(pTexture, &srvDesc, out_srv);
if (pTexture != NULL) {
pTexture->Release();
}
else
{
std::cout << "pTexture is NULL ShaderResourceView not created" << std::endl;
}
return true;
}
bool CreateDeviceD3D(HWND hWnd)
{
// Setup swap chain
DXGI_SWAP_CHAIN_DESC sd;
ZeroMemory(&sd, sizeof(sd));
sd.BufferCount = 2;
sd.BufferDesc.Width = 0;
sd.BufferDesc.Height = 0;
sd.BufferDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
sd.BufferDesc.RefreshRate.Numerator = 60;
sd.BufferDesc.RefreshRate.Denominator = 1;
sd.Flags = DXGI_SWAP_CHAIN_FLAG_ALLOW_MODE_SWITCH;
sd.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT;
sd.OutputWindow = hWnd;
sd.SampleDesc.Count = 1;
sd.SampleDesc.Quality = 0;
sd.Windowed = TRUE;
sd.SwapEffect = DXGI_SWAP_EFFECT_DISCARD;
UINT createDeviceFlags = 0;
createDeviceFlags |= D3D11_CREATE_DEVICE_DEBUG;
D3D_FEATURE_LEVEL featureLevel;
const D3D_FEATURE_LEVEL featureLevelArray[2] = { D3D_FEATURE_LEVEL_11_0, D3D_FEATURE_LEVEL_10_0, };
Attempting to Map/Unmap texture:
void UpdateCamTexture() {
D3D11_MAPPED_SUBRESOURCE mappedResource;
ZeroMemory(&mappedResource, sizeof(D3D11_MAPPED_SUBRESOURCE));
g_pd3dDeviceContext->Map(
pTexture,
0, //0,
D3D11_MAP_WRITE_DISCARD,
0,
&mappedResource);
memcpy(mappedResource.pData, listener_instance.pImgData, sizeof(listener_instance.pImgData));
// Reenable GPU access to the vertex buffer data.
g_pd3dDeviceContext->Unmap(pTexture, 0);
std::cout << "texture updated" << std::endl;
}
I don't get an error, the image is just black. I don't have debug layer enabled though.
Calling sizeof on a pointer listener_instance.pImgData is not what you want since it returns the size of a pointer type (8 on x64 architecture) and not size of array pointed by the pointer. Calling memcpy with the image data size in bytes is also not completely correct solution. See here for more details.
I will copy the answer from there just in case it's deleted.
Maximus Minimus's answer:
Check the returned pitch from your map call - you're assuming it's width * 4 (for 32-bit RGBA) but it may not be (particularly if your texture is not a power of 2 or it's width is not a multiple of 4).
You can only memcpy the entire block in one operation if pitch is equal to width * number of bytes in the format. Otherwise you must memcpy one row at a time.
Sample code, excuse C-isms:
assumes that src and dst are 32-bit RGBA data
unsigned *src; // this comes from whatever your input is
unsigned *dst = (unsigned *) msr.pData; // msr is a D3D11_MAPPED_SUBRESOURCE derived from ID3D11DeviceContext::Map
width and height come from ID3D11Texture2D::GetDesc
for (int i = 0; i < height; i++)
{
memcpy (dst, src, width * 4); // copy one row at a time because msr.RowPitch may be != (width * 4)
dst += msr.RowPitch >> 2; // msr.RowPitch is in bytes so for 32-bit data we divide by 4 (or downshift by 2, same thing)
src += width; // assumes pitch of source data is equal to width * 4
}
You can, of course, also include a test for if (msr.RowPitch == width * 4) and do a single memcpy of the entire thing if it's true.

trying to copy pixal data from cpu to gpu using map every thing runs fine but the screen comes empty directx

in my TextureHendler class, I create an empty texture using this
D3D11_TEXTURE2D_DESC textureDesc = { 0 };
textureDesc.Width = textureWidth;
textureDesc.Height = textureHeight;
textureDesc.Format = dxgiFormat;
textureDesc.Usage = D3D11_USAGE_DYNAMIC;
textureDesc.CPUAccessFlags = D3D11_CPU_ACCESS_WRITE;
textureDesc.MiscFlags = 0;
textureDesc.MipLevels = 1;
textureDesc.ArraySize = 1;
textureDesc.SampleDesc.Count = 1;
textureDesc.SampleDesc.Quality = 0;
textureDesc.BindFlags = D3D11_BIND_SHADER_RESOURCE;
hr = m_deviceResource->GetD3DDevice()->CreateTexture2D(
&textureDesc,
nullptr,
&texture);
and on runtime, I want to load data from CPU memory using the code below
Platform::Array<unsigned char>^ datapointer = GetPixelBytes();
static constexpr int BYTES_IN_RGBA_PIXEL = 4;
auto rowspan = BYTES_IN_RGBA_PIXEL * width;
D3D11_MAPPED_SUBRESOURCE ms;
auto device_context = m_deviceResource->GetD3DDeviceContext();
device_context->Map(m_texture->GetTexture2d(), 0, D3D11_MAP_WRITE_DISCARD, 0, &ms);
uint8_t* mappedData = reinterpret_cast<uint8_t*>(ms.pData);
for (int i = 0; i < datapointer->Length; i++)
{
mappedData[i] = datapointer[i];
}
device_context->Unmap(m_texture->GetTexture2d(), 0);
everything runs fine but the output screen comes black
Update :
std::shared_ptr<TextureHendler> m_texture;
TextureHendler Holds
public:
ID3D11Texture2D* GetTexture2d() { return texture.Get(); }
private:
Microsoft::WRL::ComPtr<ID3D11Texture2D> texture;
and a load function which content is shown above
here are the sample code https://github.com/AbhishekSharma-SEG/Demo_DXPlayer thanks for the help

Draw Text with FreeType (DirectX 11)

So I would like to draw text with FreeType (on DirectX 11). The problem is that I don't really understand how to create the my_draw_bitmap function (I follow this tutorial).
I get all the glyphs then convert them to bitmap, but I don't see how to convert an FT_Bitmap* to a ID3D11Texture2D* (this would - in theory - allow me to render a text)
Here is my code :
FontLoader.cpp
void FontLoader::RenderText(ID3D11Device* p_device, Text* p_text, Math::Vec2 p_position)
{
const char* text = p_text->GetText();
FT_Face face = p_text->GetFont()->GetFace();
FT_GlyphSlot slot = face->glyph;
Math::Vec2 pen = p_position;
for (unsigned int i = 0; i < strlen(text); ++i)
{
if (FT_Load_Char(face, text[i], FT_LOAD_RENDER))
continue;
// draw to our target surface
CreateTextureFromBitmap(p_device, &slot->bitmap, Math::Vec2((float)slot->bitmap_left, (float)slot->bitmap_top));
// Increment pen position
pen._x += slot->advance.x >> 6;
}
}
ID3D11Texture2D* FontLoader::CreateTextureFromBitmap(ID3D11Device* p_device, FT_Bitmap* p_bitmap, Math::Vec2 p_position)
{
D3D11_TEXTURE2D_DESC textureDesc;
textureDesc.Width = p_bitmap->width;
textureDesc.Height = p_bitmap->pitch;
textureDesc.MipLevels = textureDesc.ArraySize = 1;
textureDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
textureDesc.SampleDesc.Count = 1;
textureDesc.Usage = D3D11_USAGE_DYNAMIC;
textureDesc.BindFlags = D3D11_BIND_SHADER_RESOURCE;
textureDesc.CPUAccessFlags = D3D11_CPU_ACCESS_WRITE;
textureDesc.MiscFlags = 0;
ID3D11Texture2D *texture2D = NULL;
// don't know how and when to use p_bitmap
p_device->CreateTexture2D(&textureDesc, NULL, &texture2D);
return texture2D;
}
Thanks a lot !

MFC casting Handle into pointer and DIB to DDB conversion

I am trying to create a bitmap by hardcoding an array of pixel values, converting this array of pixels into a DIB, and then turn this DIB into a DDB. I found two functions to convert CreateBitmapFromPixels and DIBToDDB on the internet. My problem is that the program would crash at line 244. I found that, at line 243, lpbi does not retrieve information from hDIB. Then I added the code at lines 229 and 230 to see if doing the same thing in the function that created the BITMAPINFO structure would help. Still, nothing was gotten from the HBITMAP. I am wondering if there is anything wrong with casting a handle into a pointer, what does it do, and are there other ways to get the HBITMAPINFOHEADER from a handle to a DIB so I can fix the problem.
HBITMAP ColorChange2Dlg::CreateBitmapFromPixels( HDC hDC,
UINT uWidth, UINT uHeight, UINT uBitsPerPixel, LPVOID pBits)
{
if(uBitsPerPixel < 8) // NOT IMPLEMENTED YET
return NULL;
if(uBitsPerPixel == 8)
return Create8bppBitmap(hDC, uWidth, uHeight, pBits);
HBITMAP hBitmap = 0;
if ( !uWidth || !uHeight || !uBitsPerPixel )
return hBitmap;
LONG lBmpSize = uWidth * uHeight * (uBitsPerPixel/8) ;
BITMAPINFO bmpInfo = { 0 };
bmpInfo.bmiHeader.biBitCount = uBitsPerPixel;
bmpInfo.bmiHeader.biHeight = uHeight;
bmpInfo.bmiHeader.biWidth = uWidth;
bmpInfo.bmiHeader.biPlanes = 1;
bmpInfo.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
if(bmpInfo.bmiHeader.biBitCount==32) {
bmpInfo.bmiHeader.biCompression=BI_RGB;
//bmpInfo.bmiColors=NULL;
}
// Pointer to access the pixels of bitmap
UINT * pPixels = 0;
hBitmap = CreateDIBSection( hDC, (BITMAPINFO *)&
bmpInfo, DIB_RGB_COLORS, (void **)&
pPixels , NULL, 0);
if ( !hBitmap )
return hBitmap; // return if invalid bitmaps
//SetBitmapBits( hBitmap, lBmpSize, pBits);
// Directly Write
memcpy(pPixels, pBits, lBmpSize );
LPBITMAPINFOHEADER lpbi; //Line 229
lpbi = (LPBITMAPINFOHEADER)hBitmap; //Line 230
return hBitmap;
}
HBITMAP ColorChange2Dlg::DIBToDDB( HANDLE hDIB, CDC& dc )
{
LPBITMAPINFOHEADER lpbi;
HBITMAP hbm;
CPalette pal;
CPalette* pOldPal;
//CClientDC dc(NULL);
if (hDIB == NULL)
return NULL;
lpbi = (LPBITMAPINFOHEADER)hDIB; //Line 243
int nColors = lpbi->biClrUsed ? lpbi->biClrUsed : 1 << lpbi->biBitCount; //Line 244
BITMAPINFO &bmInfo = *(LPBITMAPINFO)hDIB ;
LPVOID lpDIBBits;
if( bmInfo.bmiHeader.biBitCount > 8 )
lpDIBBits = (LPVOID)((LPDWORD)(bmInfo.bmiColors +
bmInfo.bmiHeader.biClrUsed) +
((bmInfo.bmiHeader.biCompression == BI_BITFIELDS) ? 3 : 0));
else
lpDIBBits = (LPVOID)(bmInfo.bmiColors + nColors);
// Create and select a logical palette if needed
if( nColors <= 256 && dc.GetDeviceCaps(RASTERCAPS) & RC_PALETTE)
{
UINT nSize = sizeof(LOGPALETTE) + (sizeof(PALETTEENTRY) * nColors);
LOGPALETTE *pLP = (LOGPALETTE *) new BYTE[nSize];
pLP->palVersion = 0x300;
pLP->palNumEntries = nColors;
for( int i=0; i < nColors; i++)
{
pLP->palPalEntry[i].peRed = bmInfo.bmiColors[i].rgbRed;
pLP->palPalEntry[i].peGreen = bmInfo.bmiColors[i].rgbGreen;
pLP->palPalEntry[i].peBlue = bmInfo.bmiColors[i].rgbBlue;
pLP->palPalEntry[i].peFlags = 0;
}
pal.CreatePalette( pLP );
delete[] pLP;
// Select and realize the palette
pOldPal = dc.SelectPalette( &pal, FALSE );
dc.RealizePalette();
}
hbm = CreateDIBitmap(dc.GetSafeHdc(), // handle to device context
(LPBITMAPINFOHEADER)lpbi, // pointer to bitmap info header
(LONG)CBM_INIT, // initialization flag
lpDIBBits, // pointer to initialization data
(LPBITMAPINFO)lpbi, // pointer to bitmap info
DIB_RGB_COLORS ); // color-data usage
if (pal.GetSafeHandle())
dc.SelectPalette(pOldPal,FALSE);
return hbm;
}
void ColorChange2Dlg::OnBnClickedButton1()
{
// TODO: Add your control notification handler code here
CClientDC dc(this);
COLORREF *pix = (COLORREF *)malloc(255*255*sizeof(COLORREF));
//int x = 1;
if(pix!=NULL){
for(int i=0;i<255;i++)
{
for(int j=0;j<255;j++)
{
pix[i*255+j] = RGB(i,j,0);
}
}
}
CDC tempDC;
tempDC.CreateCompatibleDC(&dc);
HBITMAP dib = CreateBitmapFromPixels(tempDC.m_hDC,255,255,8*sizeof(COLORREF),(BYTE*)pix);
HBITMAP finalMap = DIBToDDB(dib,tempDC);
HBITMAP oldMap = (HBITMAP)tempDC.SelectObject(finalMap);
dc.BitBlt(201,50,255,255,&tempDC,0,0,SRCCOPY);
tempDC.SelectObject(oldMap);
tempDC.DeleteDC();
}
To write compatible code, it's better not to access bits directly at all. You can use Gradient functions and GDI or GDI+ draw functions to do anything you want.
The code you have in mind pix[i*255+j] = RGB(i,j,0); is of a 32-bit image. Each pixel points to a color. It's not a palette image where each pixel points to an entry in the color table.
If display is 32 bit (most modern computers are, but check to make sure), you can do this with the following code
CBitmap m_bitmap;
void CMyWnd::make_bitmap()
{
if (m_bitmap.GetSafeHandle()) return;
int w = 255;
int h = 255;
int *pix = new int[w*h];
for (int i = 0; i < w; i++)
for (int j = 0; j < h; j++)
pix[i + j*w] = RGB(i, j, 0);
m_bitmap.CreateBitmap(w, h, 1, 32, pix);
delete[]pix;
}
And to draw the bitmap:
void CMyWnd::paint_bitmap(CDC &dc)
{
if (!m_bitmap.GetSafeHandle()) return;
CDC memdc;
memdc.CreateCompatibleDC(&dc);
HBITMAP oldbitmap = (HBITMAP)memdc.SelectObject(m_bitmap);
BITMAP bm;
m_bitmap.GetBitmap(&bm);
dc.BitBlt(0, 0, bm.bmWidth, bm.bmHeight, &memdc, 0, 0, SRCCOPY);
memdc.SelectObject(oldbitmap);
}
void CMyWnd::OnPaint()
{
__super::OnPaint();
CClientDC dc(this);
paint_bitmap(dc);
}
Edit: For historical reasons the RGB value are saved backward as BGR. Use this function instead:
void CMyWnd::make_bitmap()
{
if (m_bitmap.GetSafeHandle()) return;
int w = 256;
int h = 256;
BYTE *pix = new BYTE[4*w*h];
for (int i = 0; i < w; i++)
{
for (int j = 0; j < h; j++)
{
int p = (i + j*w) * 4;
pix[p + 0] = 0;//blue
pix[p + 1] = i;//green
pix[p + 2] = j;//red
pix[p + 3] = 0;//not used in GDI functions
}
}
m_bitmap.CreateBitmap(w, h, 1, 32, pix);
delete[]pix;
}

How to unlock a locked bitmap

I want to unlock a locked ID2D1Bitmap I have tried m_pBitmap1->Release(); but it doesn't seem to work
hr=m_pBitmap1->CopyFromRenderTarget(nullptr, m_pRenderTarget2, nullptr); gives an access violation error:
"Unhandled exception at 0x00fb2a46 in dent_detection_sys.exe: 0xC0000005: Access violation reading location 0x00000024."
WICRect rcLock = { 0, 0, sc_bitmapWidth , sc_bitmapHeight };
IWICBitmapLock *pILock=NULL;
hr =pWICBitmap->Lock(&rcLock, WICBitmapLockWrite, &pILock);
hr=pRT->CreateSharedBitmap(
IID_IWICBitmapLock,
static_cast<void *>(pILock),
&bp2,
&m_pBitmap1
);
hr=m_pBitmap1->Release();
hr=m_pBitmap1->CopyFromRenderTarget(nullptr, m_pRenderTarget2, nullptr);
To unlock the WIC bitmap, release the IWICBitmapLock:
pILock->Release();
You should only release m_pBitmap1 when you don't want to use it anymore.
hr=m_pBitmap1->CopyFromRenderTarget(nullptr, m_pRenderTarget2, nullptr);
hr=m_pBitmap1->Release();
According to the MSDN to use a shared WIC bitmap the render target type must be D2D1_RENDER_TARGET_TYPE_SOFTWARE when the render target is created.
cdemo is a structure object with basic d2d, wic, dwrite interface pointers.
example: cdemo->d2d.factory->CreateSomething(), cdemo->wic.factory->CreateSomething(), cdemo->dwrite.factory->CreateSomething, cdemo->xaudio.factory->CreateSomething, etc.
cbmp is a pointer to a structure that has interfaces and properties related to a WIC bitmap
The following example does not work as is without some tweaks and typo fixes, but it can be used to demonstrate how to use wic for editing a bitmap and directly accessing pixels
This code assumes that the cdemo->d2d.factory and cdemo->wic.factory are already created.
#define DEBUG_FAILED_GOTO(a,b) MessageBox(m_hwnd, a, L"FAILED", MB_OK); goto b
#define DEBUG_DISPLAY(a) MessageBox(m_hwnd, a, L"DEBUG", MB_OK)
#define USING_SHARED_WIC_BITMAP
#define USING_WIC_RENDER_TARGET
#define USING_WICBMP_COPY_TO_D2DBMP
struct COMMON_WIC_BGRA { BYTE b, g, r, a };
struct COMMON_WIC_BMP
{
//// Miscelaneous variables
bool ready;
bool using_d2d_bmp;
bool using_shared_bmp;
bool using_render_tgt;
bool ready_d2d_bmp;
bool ready_shared_bmp;
bool ready_render_tgt;
UINT BPPPP; // Bit-Per-Pixel-Per-Plane
UINT stride; // cbStride = row size;
UINT buff_size; // (org_size.y * stride);
POINT org_size, clip_TpLt, padding;
POINT cur_size, clip_BtRt;
D2D1_BITMAP_PROPERTIES props_bmp; // = D2D1::BitmapProperties();
D2D1_RENDER_TARGET_PROPERTIES props_tgt; // = D2D1::RenderTargetProperties();
WICPixelFormatGUID formatGUID; // = GUID_WICPixelFormat32bppPBGRA;
WICRect rc_lock; // the lock region, usually the entire
//// Interfaces
IWICBitmap* ifc_bmp; // WIC bitmap: lock and unlock bmp data;
IWICBitmapLock* ifc_lock; // Used to access the pixels to read/write
ID2D1RenderTarget* ifc_render_tgt; // Creates a d2d render target
ID2D1Bitmap* ifc_d2d_bmp; // creates an d2d bitmap for display
ID2D1Bitmap* ifc_shared_bmp; // creates a shared bitmap for display
ID2D1SolidColorBrush* ifc_render_brush; // This is needed for the render target
//// Data pointers
BYTE* byte; // Points to a pixel's byte; 8 bits
COMMON_WIC_BGRA* wpixel; // Points to a pixel; 32 bits
};
BOOL Lock_Release (COMON_WIC_BMP *cbmp);
BOOL Lock_Start (COMMON_INTERFACE_STUFF *cdemo, COMMON_WIC_BMP *cbmp, DWORD flags);
void Create_BMP_n_Stuff (
COMMON_INTERFACE_STUFF *cdemo,
COMMON_WIC_BMP *cbmp,
int org_xsize,
int org_ysize)
{
DEBUG_DISPLAY(L"Gate 0-1 Open: started xxx process");
if (cbmp == NULL) { return E_FAIL; }
if (cdemo == NULL) { return E_FAIL; }
DEBUG_DISPLAY(L"Gate 0-2 Open: passed the sanity test");
HRESULT hr = S_OK;
ZeroMemory(cbmp, sizeof(COMMON_WIC_BMP));
// Create a Direct2D render target.
if (cdemo->d2d.hwnd_tgt == NULL)
{
RECT rc;
GetClientRect(m_hwnd, &rc);
D2D1_SIZE_U size = D2D1::SizeU((rc.right - rc.left), (rc.bottom - rc.top));
cdemo->d2d.props_tgt = D2D1::HwndRenderTargetProperties(m_hwnd, size);
cdemo->d2d.props_tgt_type = D2D1_RENDER_TARGET_TYPE_SOFTWARE;
cdemo->d2d.props_bmp = D2D1::BitmapProperties();
hr = cdemo->d2d.factory->CreateHwndRenderTarget(
cdemo->d2d.props_tgt_type,
cdemo->d2d.props_tgt,
&cdemo->d2d.hwnd_tgt);
if (FAILED(hr)) { goto CleanUp; }
}
DEBUG_DISPLAY(L"Gate 1 Open: hwnd_tgt created");
cbmp->ready = false; // type is: bool
// this option is compatible to D2D bitmap without conversion
cbmp->formatGUID = GUID_WICPixelFormat32bppPBGRA; // type is: WICPixelFormatGUID
cbmp->buff_size = 0; // type is: UINT32
cbmp->stride = 0; // type is: UINT32
cbmp->clip_TpLt.x = 0; // type is: POINT or POINTS
cbmp->clip_TpLt.y = 0;
cbmp->clip_BtRt.x = cbmp->org_size.x = org_xsize; // type is: POINT or POINTS
cbmp->clip_BtRt.y = cbmp->org_size.y = org_ysize;
cbmp->byte = NULL; // type is: pointer to BYTE, BYTE*
cbmp->pixel = NULL; // type is: pointer to COMMON_WIC_BGRA, COMMON_WIC_BGRA*
cbmp->ifc_bmp = NULL; // type is: IWICBitmap*
cbmp->ifc_d2d_bmp = NULL; // type is: ID2D1Bitmap*
cbmp->ifc_lock = NULL; // type is: IWICBitmapLock*
cbmp->ifc_shared_bmp = NULL; // type is: ID2D1Bitmap*
cbmp->ifc_render_tgt = NULL; // type is: ID2D1RenderTarget*
cbmp->ifc_render_brush = NULL; // type is: ID2D1SolidColorBrush*
//D2D1_BITMAP_PROPERTIES props_bmp; = D2D1::BitmapProperties();
//D2D1_RENDER_TARGET_PROPERTIES props_tgt; = D2D1::RenderTargetProperties();
//bool ready;
//bool using_d2d_bmp;
//bool using_shared_bmp;
//bool using_render_tgt;
//bool ready_d2d_bmp;
//bool ready_shared_bmp;
//bool ready_render_tgt;
//UINT BPPPP; // Bit-Per-Pixel-Per-Plane
if (cdemo->wic.factory == NULL)
{ // (re)create the WIC factory
hr = CoCreateInstance(
CLSID_WICImagingFactory,
NULL,
CLSCTX_INPROC_SERVER,
IID_IWICImagingFactory,
reinterpret_cast<void **>(&cdemo->wic.factory));
if (FAILED(hr)) { goto CleanUp; }
}
hr = cdemo->wic.factory->CreateBitmap(
cbmp->org_size.x,
cbmp->org_size.y,
cbmp->formatGUID,
WICBitmapCacheOnDemand,
&cbmp->ifc_bmp);
// Experimental debug
//if (FAILED(hr)) { DEBUG_FAILED_GOTO(L"FAILED creating wic bitmap", CleanUp); }
if (FAILED(hr)) { goto CleanUp; }
DEBUG_DISPLAY(L"Gate 2 Open: created the WIC bitmap");
// type is: WICRect;
cbmp->rc_lock = { 0, 0, (UINT)cbmp->org_size.x, (UINT)cbmp->org_size.y };
hr = cbmp->ifc_bmp->Lock(&cbmp->rc_lock, WICBitmapLockWrite, &cbmp->ifc_lock);
hr = cbmp->ifc_lock->GetStride(&cbmp->stride); //row size = (xsize*BPPP) + xpadding
hr = cbmp->ifc_lock->GetDataPointer(&cbmp->buff_size, &cbmp->byte);
cbmp->wpixel = (COMMON_WIC_BRGA *)cbmp->byte;
// clear the bitmap
ZeroMemory(cbmp->byte, cbmp->buff_size);
#ifdef USING_SHARED_WIC_BITMAP
cbmp->props_bmp = D2D1:BitmapProperties();
hr = demo->d2d.hwnd_tgt->CreateSharedBitmap(
IID_IWICBitmapLock,
(void*)cbmp->ifc_lock,
&cbmp->props_bmp,
&cbmp->ifc_shared_bmp);
if (SUCCEDED(hr))
{
cbmp->using_shared_bmp = true;
DEBUG_DISPLAY(L"Gate 4-1 Open: created shared wic bitmap");
}
#endif
#ifdef USING_WICBMP_COPY_TO_D2DBMP
hr = cdemo->d2d.factory->CreateBitmapFromWicBitmap(
cbmp->ifc_bmp,
&cbmp->props_bmp,
&cbmp->ifc_d2d_bmp);
if (SUCCEDED(hr))
{
cbmp->using_d2d_bmp = true;
DEBUG_DISPLAY(L"Gate 4-2 Open: created d2d bitmap ");
}
#endif
#ifdef USING_WIC_RENDER_TARGET
cbmp->props_tgt = D2D1::RenderTargetProperties();
cbmp->props_tgt.type = D2D1_RENDER_TARGET_TYPE_SOFTWARE;
hr = cdemo->d2d.factory->CreateWicBitmapRenderTarget(
cbmp->ifc_bmp,
&cbmp->props_tgt,
&cbmp->ifc_render_tgt);
if (SUCCEDED(hr))
{
hr = cbmp->ifc_render_tgt->CreateSolidColorBrush(
{ 1.0f, 1.0f, 1.0f, 1.0f }, // Solid white
&cbmp->ifc_render_brush);
cbmp->using_shared_bmp = true;
DEBUG_DISPLAY(L"Gate 4-3 Open: created wic render target and brush");
}
#endif
if (FAILED(hr)) { goto CleanUp; }
cbmp->ready = true;
// Rules of engagement if using all possible combinations above
// 1) After SafeRelease(&cbmp->ifc_lock) you cannot use cbmp->byte or cbmp->wpixel
// 2) To use cbmp->ifc_render_tgt you must first SafeRelease(cbmp->ifc_lock) and
// SafeRelease(&cbmp->ifc_shared_bmp). Later reinitialize them as needed.
// 3) To display the wic bitmap (cbmp->ifc_bmp) onto cdemo->d2d.hwnd_tgt:
// you cannot copy the wic bitmap (cbmp->ifc_bmp) directly to an hwnd render target
// option 1: This is whole point of creating the shared bmp
// cdemo->d2d.hwnd_tgt->DrawBMP( [ &dst_rc, ] cbmp->ifc_shared_bmp);
// option 2: Copy the pixels to the d2d bitmap, copy the d2d bitmap to the target
// cbmp->ifc_d2d_bmp->CopyFromMemory(cbmp->byte, &dst_rc, cbmp->stride);
// cdemo->d2d.hwnd_tgt->DrawBMP( [ &dst_rc, ] cbmp->ifc_d2d_bmp);
// option 3: Copy from the render target to the d2d bitmap
// cbmp->ifc_d2d_bmp->CopyFromRenderTarget(&pt_dst, cbmp->ifc_render_tgt, &src_rc);
// cdemo->d2d.hwnd_tgt->DrawBMP( [ &dst_rc, ] cbmp->ifc_d2d_bmp);
// 4) When drawing directly to the wic bitmap either use cbmp->ifc_render_tgt or
// cbmp->ifc_lock + cbmp->byte + your own algorithms to draw shapes
//
// 5) for simplicty: it can get confusing when trying to use all methods
option 1: use the ifc_lock with the ifc_shared_bmp + your own algorithms
option 2: use the ifc_render_tgt with the ifc_d2d_bmp
// Example: Draw a filled 12x15 rectangle example:
int x = 20, byte_col = 0, wpixel_col = 0, sizey = 12;
int y = 35, byte_row = 0, wpixel_row = 0, sizex = 15;
D2D1_COLOR_F d2d_colr = { 0.50f, 0.10f, 0.80f, 1.00f }; //some random color
COMMON_WIC_BGRA wic_colr = { 0, 0, 0, 0 };
D2D1_POINT_2U d2d_pt_dst_f = { 0, 0 };
D2D_RECT_F d2d_outputrect = { 0.0f, 0.0f, 0.0f, 0.0f };
D2D1_RECT_F d2d_dst_rcf =
{ 0.0f, 0.0f, (FLOAT)cbmp->org_size.x, (FLOAT)cbmp->org_size.y };
D2D1_RECT_U d2d_src_rcu =
{ 0, 0, (UINT32)cbmp->org_size.x, (UINT32)cbmp->org_size.y };
WIC_RECT_U wic_dst_rcu =
{ 0, 0, (UINT32)cbmp->org_size.x, (UINT32)cbmp->org_size.y };
WIC_RECT_U wic_src_rcu = wic_dst_rcu
// must release the lock and shared bitmap before using the render target
Lock_End(cbmp);
// This should look familiar
d2d_outputrect = { (FLOAT)x, (FLOAT)y, (FLOAT)(x+sizex-1), (FLOAT)(y+sizey-1) };
cbmp->ifc_render_tgt->BeginDraw();
cbmp->ifc_render_brush->SetColor(d2d_colr);
cbmp->ifc_render_tgt->SetTransform(D2D1::IdentityMatrix());
cbmp->ifc_render_tgt->FillRectangle(&d2d_outputrect, cbmp->ifc_render_brush);
hr = cbmp->ifc_render_tgt->EndDraw();
// display the wic bitmap on the hwnd render target
hr = cbmp->ifc_d2d_bmp->CopyFromRenderTarget(
&d2d_pt_dst,
cbmp->ifc_render_tgt,
&d2d_src_rc);
hr = cdemo->d2d.hwnd_tgt->DrawBMP(&d2d_dst_rc, cbmp->ifc_d2d_bmp);
// Alternative: using the ifc_lock with the ifc_shared_bmp + home grown algorithms
if (!Lock_Start(cdemo, cbmp, WICBitmapLockWrite)) { goto CleanUp; }
// convert D2D1_COLOR_F { b, g, r, a} to BYTE { b, g, r, a }
wic_colr.b = (BYTE)ceil(d2d_colr.b * 255);
wic_colr.g = (BYTE)ceil(d2d_colr.g * 255);
wic_colr.r = (BYTE)ceil(d2d_colr.r * 255);
wic_colr.a = (BYTE)ceil(d2d_colr.a * 255);
for (int run_y = 0; run_y < sizey; ++run_y)
{
// clipping for the y values
if (((run_y + y) < cbmp->clip_TpLt.y) || ((run_y + y) >= clip_BtRt.y))
{ continue; }
// convert the y to a byte position
byte_row = ((run_y + y) * cbmp->stride);
wpixel_row = ((run_y + y) * cbmp->org_size.x) + cbmp->padding.x; //optional
for (int run_x = 0; run_x < sizex; ++run_x)
{
// clipping for the x values
if (((run_x + x) < cbmp->clip_TpLt.x) || ((run_x + x) >= clip_BtRt.x))
{ continue; }
// convert the x to an offset position
byte_col = ((run_x + x) * 4); // must multiply by 4 bytes (b, g, r, a)
wpixel_col = (run_x + x); // cbmp->wpixel points to every 4 bytes
// access the pixels by means of pointer[(y_position + x_offset)]
cbmp->byte[(byte_row + byte_col + 0)] = wic_colr.b;
cbmp->byte[(byte_row + byte_col + 1)] = wic_colr.g;
cbmp->byte[(byte_row + byte_col + 2)] = wic_colr.r;
cbmp->byte[(byte_row + byte_col + 3)] = wic_colr.a;
cbmp->wpixel[(wpixel_row + wpixel_col)] = wic_colr; // Alternative
// Another method
cbmp->wpixel[(wpixel_row + wpixel_col)].b = wic_colr.b; // Alternatives
cbmp->wpixel[(wpixel_row + wpixel_col)].g = wic_colr.g; // Alternatives
cbmp->wpixel[(wpixel_row + wpixel_col)].r = wic_colr.r; // Alternatives
cbmp->wpixel[(wpixel_row + wpixel_col)].a = wic_colr.a; // Alternatives
}
}
// display the wic bitmap on the hwnd render target
cdemo->d2d.hwnd_tgt->DrawBMP(&dst_rc, cbmp->ifc_shared_bmp);
// Optionally release the lock after every use
// Lock_Release(cbmp);
return; // commnent out if cleanup is required
CleanUp:
// SafeRelease everything that needs to be released
}
BOOL Lock_Start (
COMMON_INTERFACE_STUFF *cdemo,
COMMON_WIC_BMP *cbmp,
DWORD flags)
{
if (cdemo == NULL) { return FALSE; }
//if (!cdemo->ready) { CreateResouces(cdemo); }
if (cbmp == NULL) { return FALSE; }
if (cbmp->ifc_lock != NULL) { return TRUE; }
SafeRelease(&cbmp->ifc_lock);
hr = cbmp->ifc_bmp->Lock(&cbmp->rc_lock, flags, &cbmp->ifc_lock);
if (FAILED(hr)) { return FALSE; }
hr = cbmp->ifc_lock->GetStride(&cbmp->stride);
hr = cbmp->ifc_lock->GetDataPointer(&cbmp->buff_size, &cbmp->byte);
cbmp->wpixel = (COMMON_WIC_BGRA *)cbmp->byte;
// recreate the shared bitmap
SafeRelease(&cbmp->ifc_shared_bmp);
hr = cdemo->d2d.factory->CreateSharedBitmap(
IID_IWICBitmapLock,
(void*)cbmp->ifc_lock,
&cbmp->props_bmp,
&cbmp->ifc_shared_bmp);
return TRUE;
}
BOOL Lock_Release (COMON_WIC_BMP *cbmp)
{
if (cbmp == NULL) { return FALSE; }
if (cbmp->ifc_lock == NULL) { return TRUE; }
SafeRelease(&cbmp->ifc_lock);
SafeRelease(&cbmp->ifc_shared_bmp);
cbmp->byte = NULL;
cbmp->wpixel = NULL;
if (cbmp->using_render_tgt) { cbmp->ready_render_tgt = true; }
return TRUE;
}