将BITMAPINFOHEADER图像数据写入IDirect3DTexture9

时间:2011-06-22 22:21:38

标签: c++ bitmap textures directx-9

我正在编写一个DX9渲染器,目前正致力于播放AVI电影文件。我已经能够使用AVIStreamGetFrame()检索任何指定的帧,它返回一个打包的DIB,从那里我希望能够将该位图数据复制到已存在的IDirect3DTexture9 *

我的问题是缺乏对位图文件格式的理解,并且知道如何将BITMAPINFOHEADER提供的像素数据转换为IDirect3DTexture9可以解释的格式。

我首先创建我的DX9纹理:

LPBITMAPINFO bmpInfo = m_pVideoData->GetVideoFormat();
D3DXCreateTexture(LtGEngine::GetInstance()->GetDevice(), 
                  bmpInfo->bmiHeader.biWidth, 
                  bmpInfo->bmiHeader.biHeight, 
                  D3DX_DEFAULT, 
                  0, 
                  D3DFMT_A8R8G8B8,   // <- DETERMINE HOW?
                  D3DPOOL_MANAGED,   // <- OR D3DPOOL_SYSTEMMEM? 
                  &m_pD3DTexture);

我在这里提出的问题被列为上述评论。当我得到BITMAPINFO并且例如它读取bmpInfo.bmiHeader.biBitCount = 8(或16等)这是否意味着我需要相应地更改D3DFMT_ *?

稍后,当我想要渲染的帧LPBITMAPINFOHEADER时,我迷失了对pBits函数返回的IDirect3DTexture9::LockRect()的处理方式。以下是我到目前为止的情况:

// Retrieve a frame from the video data as a BITMAPINFOHEADER
LPBITMAPINFOHEADER pBmpInfoHeader;
m_pVideoData->GetVideoFrame(0, 0, &pBmpInfoHeader);

D3DLOCKED_RECT rect;
if(FAILED(m_pD3DTexture->LockRect(0, &rect, NULL, 0)))
{
    m_pD3DTexture->UnlockRect(0);
}
DWORD* pDest = (DWORD*)rect.pBits;
// Now what to copy from pBmpInfoHeader?

是否有任何API调用对我这样做我还没有看到过?或者有人知道比这更简单的方法吗?感谢阅读/帮助。

1 个答案:

答案 0 :(得分:1)

搞定了!

要考虑的情侣注意事项。我的AVI文件(在这种情况下为单帧/位图)采用16位格式,因此我必须使用D3DFMT_X1R5G5B5创建目标纹理。此外,位图是颠倒存储的,所以我不得不反转指针并向后读取每一行。

以下是代码:

// Retrieve a frame from the video data as a BITMAPINFOHEADER
LPBITMAPINFOHEADER pBmpInfoHeader;
m_pVideoData->GetVideoFrame(0, 0, &pBmpInfoHeader);

// Get dimentions
long nWidth = pBmpInfoHeader->biWidth;
long nHeight = pBmpInfoHeader->biHeight;

// Bitmap width correction (might not be needed...)
if (nWidth % 4 != 0)
    nWidth = nWidth + (4 - nWidth%4);

// Get Pixel data (should be after the header in memory)
WORD bitCount = pBmpInfoHeader->biBitCount;
DWORD size = nWidth * nHeight * bitCount/8;
BYTE *pPixelSrc = (BYTE *)pBmpInfoHeader + sizeof(pBmpInfoHeader);

// Lock the texture so we can write this frame's texel data
D3DLOCKED_RECT lock;
if(FAILED(m_pD3DTexture->LockRect(0, &lock, NULL, 0)))
{
    m_pD3DTexture->UnlockRect(0);
    return;
}

int iNumBytesPerRowSrc = pBmpInfoHeader->biWidth * (pBmpInfoHeader->biBitCount/8);  
int iNumBytesPerRowDst = lock.Pitch;
int iNumBytesToCopyPerRow = min(iNumBytesPerRowSrc, iNumBytesPerRowDst);

// Bitmap data is stored upside down
// Start at the end and work backwards
pPixelSrc += (iNumBytesPerRowSrc * nHeight);

// Store a pointer to the texture pixel data and write new data
BYTE* ucTexDst = (BYTE *)lock.pBits;
for(int y = 0; y < nHeight; ++y)
{
    pPixelSrc -= iNumBytesPerRowSrc;
    memcpy(ucTexDst, pPixelSrc, iNumBytesToCopyPerRow);
    ucTexDst += iNumBytesPerRowDst;
}

// Unlock texture so gfx card can resume its business
m_pD3DTexture->UnlockRect(0);