Click here to Skip to main content
15,886,258 members
Articles / Desktop Programming / WPF

Introduction to D3DImage

Rate me:
Please Sign up or sign in to vote.
5.00/5 (77 votes)
11 Aug 2008CPOL24 min read 415.8K   18.4K   219  
.NET 3.5 SP1 is here! It's time to break out your DirectX skills. This article provides the information necessary to get started using a new DirectX interop feature in WPF called D3DImage.
#include <Windows.h>
#include <mmsystem.h>
#include <d3dx9.h>
#include <strsafe.h>

#define WIDTH 300
#define HEIGHT 300

typedef HRESULT (WINAPI *DIRECT3DCREATE9EX)(UINT SDKVersion, IDirect3D9Ex**);

DIRECT3DCREATE9EX       g_pfnCreate9Ex  = NULL;
BOOL                    g_is9Ex         = FALSE;
LPDIRECT3D9             g_pD3D          = NULL;
LPDIRECT3D9EX           g_pD3DEx        = NULL;
LPDIRECT3DDEVICE9       g_pd3dDevice    = NULL;
LPDIRECT3DDEVICE9EX     g_pd3dDeviceEx  = NULL;
LPDIRECT3DSURFACE9      g_pd3dSurface   = NULL;
LPDIRECT3DVERTEXBUFFER9 g_pVB           = NULL;


LRESULT WINAPI MsgProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
    return DefWindowProc(hWnd, msg, wParam, lParam);
}


WNDCLASSEX g_wc = { sizeof(WNDCLASSEX), CS_CLASSDC, MsgProc, 0L, 0L,
      GetModuleHandle(NULL), NULL, NULL, NULL, NULL, L"Foo", NULL };


struct CUSTOMVERTEX
{
    FLOAT x, y, z;
    DWORD color;
};


#define D3DFVF_CUSTOMVERTEX (D3DFVF_XYZ|D3DFVF_DIFFUSE)


VOID SetupMatrices()
{
    // Set up rotation matrix
    D3DXMATRIXA16 matWorld;
    UINT  iTime  = timeGetTime() % 1000;
    FLOAT fAngle = iTime * (2.0f * D3DX_PI) / 1000.0f;
    D3DXMatrixRotationY(&matWorld, fAngle);
    g_pd3dDevice->SetTransform(D3DTS_WORLD, &matWorld);

    // Set up view matrix
    D3DXVECTOR3 vEyePt(0.0f, 3.0f,-4.0f);
    D3DXVECTOR3 vLookatPt(0.0f, 0.0f, 0.0f);
    D3DXVECTOR3 vUpVec(0.0f, 1.0f, 0.0f);
    D3DXMATRIXA16 matView;
    D3DXMatrixLookAtLH(&matView, &vEyePt, &vLookatPt, &vUpVec);
    g_pd3dDevice->SetTransform(D3DTS_VIEW, &matView);

    // Set up projection matrix
    D3DXMATRIXA16 matProj;
    D3DXMatrixPerspectiveFovLH(&matProj, D3DX_PI/4, 1.0f, 1.0f, 100.0f);
    g_pd3dDevice->SetTransform(D3DTS_PROJECTION, &matProj);
}


DWORD GetVertexProcessingCaps()
{
    D3DCAPS9 caps;
    DWORD dwVertexProcessing = D3DCREATE_SOFTWARE_VERTEXPROCESSING;
    if (SUCCEEDED(g_pD3D->GetDeviceCaps(D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, &caps)))
    {
        if ((caps.DevCaps & D3DDEVCAPS_HWTRANSFORMANDLIGHT) == D3DDEVCAPS_HWTRANSFORMANDLIGHT)
        {
            dwVertexProcessing = D3DCREATE_HARDWARE_VERTEXPROCESSING;
        }
    }
    return dwVertexProcessing;
}


void InitializeD3D(HWND hWnd, D3DPRESENT_PARAMETERS d3dpp)
{
    // initialize Direct3D
    if (NULL == (g_pD3D = Direct3DCreate9(D3D_SDK_VERSION)))
    {
        return;
    }

    // determine what type of vertex processing to use based on the device capabilities
    DWORD dwVertexProcessing = GetVertexProcessingCaps();

    // create the D3D device
    if (FAILED(g_pD3D->CreateDevice(D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, hWnd,
        dwVertexProcessing | D3DCREATE_MULTITHREADED | D3DCREATE_FPU_PRESERVE,
        &d3dpp, &g_pd3dDevice)))
    {
        return;
    }
}


void InitializeD3DEx(HWND hWnd, D3DPRESENT_PARAMETERS d3dpp)
{
    // initialize Direct3D using the Ex function
    if (FAILED((*g_pfnCreate9Ex)(D3D_SDK_VERSION, &g_pD3DEx)))
    {
        return;
    }

    // obtain the standard D3D interface
    if (FAILED(g_pD3DEx->QueryInterface(__uuidof(IDirect3D9), reinterpret_cast<void **>(&g_pD3D))))
    {
        return;
    }

    // determine what type of vertex processing to use based on the device capabilities
    DWORD dwVertexProcessing = GetVertexProcessingCaps();

    // create the D3D device using the Ex function
    if (FAILED(g_pD3DEx->CreateDeviceEx(D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, hWnd,
        dwVertexProcessing | D3DCREATE_MULTITHREADED | D3DCREATE_FPU_PRESERVE,
        &d3dpp, NULL, &g_pd3dDeviceEx)))
    {
        return;
    }

    // obtain the standard D3D device interface
    if (FAILED(g_pd3dDeviceEx->QueryInterface(__uuidof(IDirect3DDevice9), reinterpret_cast<void **>(&g_pd3dDevice))))
    {
        return;
    }
}


extern "C" __declspec(dllexport) LPVOID WINAPI InitializeScene()
{
    // vertices for geometry
    CUSTOMVERTEX g_Vertices[] =
    {
        { -1.0f,-1.0f, 0.0f, 0xffff0000, },
        {  1.0f,-1.0f, 0.0f, 0xff0000ff, },
        {  0.0f, 1.0f, 0.0f, 0xC0ffffff, },
    };

    // set up the structure used to create the D3DDevice
    D3DPRESENT_PARAMETERS d3dpp;
    ZeroMemory(&d3dpp, sizeof(d3dpp));
    d3dpp.Windowed = TRUE;
    d3dpp.BackBufferHeight = 1;
    d3dpp.BackBufferWidth = 1;
    d3dpp.SwapEffect = D3DSWAPEFFECT_DISCARD;
    d3dpp.BackBufferFormat = D3DFMT_A8R8G8B8;

    // create the device's window
    RegisterClassEx(&g_wc);
    HWND hWnd = CreateWindow(L"Foo", L"Foo", WS_OVERLAPPEDWINDOW, 
        0, 0, 0, 0, NULL, NULL, g_wc.hInstance, NULL);

    // Vista requires the D3D "Ex" functions for optimal performance.  
    // The Ex functions are only supported with WDDM drivers, so they 
    // will not be available on XP.  As such, we must use the D3D9Ex 
    // functions on Vista and the D3D9 functions on XP.

    // Rather than query the OS version, we can simply check for the
    // 9Ex functions, since this is ultimately what we care about.
    HMODULE hD3D9 = LoadLibrary(TEXT("d3d9.dll"));
    g_pfnCreate9Ex = (DIRECT3DCREATE9EX)GetProcAddress(hD3D9, "Direct3DCreate9Ex");
    g_is9Ex = (g_pfnCreate9Ex != NULL);
    FreeLibrary(hD3D9);

    if (g_is9Ex)
    {
        InitializeD3DEx(hWnd, d3dpp);
    }
    else
    {
        InitializeD3D(hWnd, d3dpp);
    }

    // create and set the render target surface
    // it should be lockable on XP and nonlockable on Vista
    if (FAILED(g_pd3dDevice->CreateRenderTarget(WIDTH, HEIGHT, 
        D3DFMT_A8R8G8B8, D3DMULTISAMPLE_NONE, 0, 
        !g_is9Ex, // lockable
        &g_pd3dSurface, NULL)))
    {
        return NULL;
    }
    g_pd3dDevice->SetRenderTarget(0, g_pd3dSurface);

    // turn off culling to view both sides of the triangle
    g_pd3dDevice->SetRenderState(D3DRS_CULLMODE, D3DCULL_NONE);
    
    // turn off D3D lighting to use vertex colors
    g_pd3dDevice->SetRenderState(D3DRS_LIGHTING, FALSE);

    // create vertex buffer
    if (FAILED(g_pd3dDevice->CreateVertexBuffer(3*sizeof(CUSTOMVERTEX),
        0, D3DFVF_CUSTOMVERTEX, D3DPOOL_DEFAULT, &g_pVB, NULL)))
    {
        return NULL;
    }

    // fill vertex buffer
    VOID* pVertices;
    if (FAILED(g_pVB->Lock(0, sizeof(g_Vertices), (void**)&pVertices, 0)))
    {    
        return NULL;
    }
    memcpy(pVertices, g_Vertices, sizeof(g_Vertices));
    g_pVB->Unlock();

    return g_pd3dSurface;
}


extern "C" __declspec(dllexport) void WINAPI RenderScene(LPSIZE pSize)
{
    // clear the surface to transparent
    g_pd3dDevice->Clear(0, NULL, D3DCLEAR_TARGET, D3DCOLOR_ARGB(0, 0, 0, 0), 1.0f, 0);

    // render the scene
    if (SUCCEEDED(g_pd3dDevice->BeginScene()))
    {
        // setup the world, view, and projection matrices
        SetupMatrices();

        // render the vertex buffer contents
        g_pd3dDevice->SetStreamSource(0, g_pVB, 0, sizeof(CUSTOMVERTEX));
        g_pd3dDevice->SetFVF(D3DFVF_CUSTOMVERTEX);
        g_pd3dDevice->DrawPrimitive(D3DPT_TRIANGLESTRIP, 0, 1);

        // end the scene
        g_pd3dDevice->EndScene();
    }

    // return the full size of the surface
    pSize->cx = WIDTH;
    pSize->cy = HEIGHT;
}


extern "C" __declspec(dllexport) VOID WINAPI ReleaseScene()
{
    UnregisterClass(NULL, g_wc.hInstance);

    if (g_pVB != NULL)
        g_pVB->Release();

    if (g_pd3dDevice != NULL)
        g_pd3dDevice->Release();

    if (g_pd3dDeviceEx != NULL)
        g_pd3dDeviceEx->Release();

    if (g_pD3D != NULL)
        g_pD3D->Release();

    if (g_pD3DEx != NULL)
        g_pD3DEx->Release();

    if (g_pd3dSurface != NULL)
        g_pd3dSurface->Release();
}

By viewing downloads associated with this article you agree to the Terms of Service and the article's licence.

If a file you wish to view isn't highlighted, and is a text file (not binary), please let us know and we'll add colourisation support for it.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
United States United States
Dr. WPF is a WPF Disciple! Check out the doctor's blog and bio for more information.

Comments and Discussions