Replace D3DX With Your Own Code

Let’s write a replacement for D3DXCreateTextureFromResource.

Yesterday I put some code that calls a D3DX function in a published program that I maintain. D3DX was a bundle of helper functions for Direct3D 9 which Microsoft deprecated in 2012. I’m writing this in 2018. The function was this one:

D3DXCreateTextureFromResource

I thought to myself, “It’s deprecated, but Microsoft is so fanatically committed to backward compatibility that I can probably still use it.”

Microsoft’s documentation says the required library is D3dx9.lib.

The next day a bunch of people reported that the new build wouldn’t run because the operating system couldn’t find d3dx9_43.dll. Apparently this happened only on laptops running Windows 10. There was no problem on desktop machines running Windows 10 or on any machine running an earlier version of Windows.

So I wrote a replacement for D3DXCreateTextureFromResource. My new code’s not as general-purpose as the D3DX function because it makes assumptions about the pixel format, but it does what I need it to do.

//-------------------------------
//  CREATE TEXTURE FROM RESOURCE
//  Assumes D3DFMT_A8R8G8B8 / 
//  PixelFormat32bppARGB
//  Returns 0 on failure
//-------------------------------

#include <d3d9.h>
#include <gdiplus.h>
using namespace Gdiplus;

IDirect3DTexture9 * 
create_texture_from_resource ( 
	IDirect3DDevice9 * pDev, 
	HMODULE hModule, 
	unsigned uResource )
{
   auto pBm = 
      Gdiplus::Bitmap::FromResource ( 
         hModule, 
         MAKEINTRESOURCE(uResource) );

   if ( Status::Ok != 
      pBm->GetLastStatus() )
         return 0;

   UINT uDimY = pBm->GetHeight();
   UINT uDimX = pBm->GetWidth();

   IDirect3DTexture9 * pTex = 0;

   HRESULT hr = 
      pDev->CreateTexture (
         uDimX,
         uDimY,
         1,
         0,
         D3DFMT_A8R8G8B8,
         D3DPOOL_MANAGED,
         &pTex,
         NULL );

   if ( FAILED(hr) )
      return 0;

   //----------------------
   //  SOURCE POINTER
   //----------------------

   BitmapData bd;

   Rect rect ({0,0,(int)uDimX, 
      (int)uDimY});

   if ( Status::Ok != 
      pBm->LockBits ( 
         &rect, 
         ImageLockModeRead, 
         PixelFormat32bppARGB, 
         &bd) )
         return 0;

   unsigned char * pSrcPixels = 
      (unsigned char*) bd.Scan0;

   //---------------------------
   //  DEST POINTER
   //---------------------------

   D3DLOCKED_RECT lr;

   if ( D3D_OK != 
      pTex->LockRect ( 
	     0, &lr, 0, 0) )
   {
      pTex->Release();
      delete pBm;
      return 0;
   }

   unsigned char * pDestPixels = 
      (unsigned char*)lr.pBits;

   //--------------------------------
   //  COPY
   //  By row in case strides differ.
   //--------------------------------

   for ( size_t y = 0; y < uDimY; y++ )
   {
      memcpy ( pDestPixels, 
         pSrcPixels, uDimX * sizeof(DWORD) );
      pSrcPixels += bd.Stride;
      pDestPixels += lr.Pitch;
   }

   pBm->UnlockBits ( &bd );
   delete pBm;

   pTex->UnlockRect(0);

   return pTex;
}

This page was first published on February 25, 2018, last revised on June 1, 2021, and last republished on June 20, 2021.

Comments