Render overlays using GDI+ on a Direct3D9 app

Started by
21 comments, last by dario_ramos 14 years, 4 months ago
I'm SO close... By setting these render states:

// Device state would normally be set hereg_pd3dDevice->SetRenderState( D3DRS_LIGHTING, FALSE );g_pd3dDevice->SetRenderState(D3DRS_ALPHABLENDENABLE, TRUE);g_pd3dDevice->SetRenderState(D3DRS_SRCBLEND, D3DBLEND_SRCALPHA);g_pd3dDevice->SetRenderState(D3DRS_DESTBLEND, D3DBLEND_INVSRCALPHA);


The texture is now transparent, and I can still see the red line. But the triangle disappeared! Here's how I defined the vertices:

HRESULT InitVB(){    // Initialize three Vertices for rendering a triangle    CUSTOMVERTEX Vertices[] =    {        { 300.0f,  50.0f, 0.5f, 1.0f, 0xffff0000, }, // x, y, z, rhw, color        { 400.0f, 250.0f, 0.5f, 1.0f, 0xff00ff00, },        {  200.0f, 250.0f, 0.5f, 1.0f, 0xff00ffff, },    };        // Initialize four vertices for a textured quad	CUSTOMVERTEX2 Vertices2[] =	{		{0, 0, 0, 1.0f, 0x00ffffff, 0, 0 },	//x, y, z, rhw, colour, u, v		{256.0f, 0, 0, 1.0f, 0x00ffffff, 1.0f, 0 },		{256.0f, 256.0f, 0, 1.0f, 0x00ffffff, 1.0f, 1.0f },		{0, 256.0f, 0, 1.0f, 0x00ffffff, 0, 1.0f }	};    // Create the vertex buffer. Here we are allocating enough memory    // (from the default pool) to hold all our 3 custom Vertices. We also    // specify the FVF, so the vertex buffer knows what data it contains.    if( FAILED( g_pd3dDevice->CreateVertexBuffer(	3 * sizeof( CUSTOMVERTEX ),			D3DUSAGE_WRITEONLY, //TODO: Fixes D3D warning			D3DFVF_CUSTOMVERTEX,			D3DPOOL_DEFAULT,			&g_pVB,			NULL ) ) )    {        return E_FAIL;    }	if( FAILED( g_pd3dDevice->CreateVertexBuffer(	4 * sizeof( CUSTOMVERTEX2 ),													D3DUSAGE_WRITEONLY, //TODO: Fixes D3D warning			D3DFVF_CUSTOMVERTEX2,			D3DPOOL_DEFAULT,			&g_pVBTQ,			NULL ) ) )    {        return E_FAIL;    }    // Now we fill the vertex buffer. To do this, we need to Lock() the VB to    // gain access to the Vertices. This mechanism is required becuase vertex    // buffers may be in device memory.    VOID* pVertices;    if( FAILED( g_pVB->Lock( 0, sizeof( Vertices ), ( void** )&pVertices, 0 ) ) )        return E_FAIL;		memcpy( pVertices, Vertices, sizeof( Vertices ) );    g_pVB->Unlock();	VOID* pVertices2;    if( FAILED( g_pVBTQ->Lock( 0, sizeof( Vertices2 ), ( void** )&pVertices2, 0 ) ) )        return E_FAIL;		memcpy( pVertices2, Vertices2, sizeof( Vertices2 ) );    g_pVBTQ->Unlock();    return S_OK;}


To see how I render these, check the render loop on one of the posts above (it's still the same)

[Edited by - dario_ramos on December 7, 2009 7:39:05 AM]
Advertisement
Hi Dario

Ive done this in the past, and ended up using the same method you are working towards; using "bitmap(width, height, lockedRect.Pitch, PixelFormat32bppARGB , (BYTE*)lockedRect.pBits);" that is. It works fine, not the fastest code in the world, but great for quickly adding overlay information and shapes.

From your code snippets I would say to get the triangle back, I think you need to disable the texture selection when you draw the triangle.

Add the line

g_pd3dDevice->SetTexture(0, NULL);

above the line where you draw the first triangle.

Apart from that, I cant see much different to what Ive done previously.

Cheers
Quote:
Add the line

g_pd3dDevice->SetTexture(0, NULL);

above the line where you draw the first triangle.


That did it! Thanks, buzzw4, you're a lifesaver!!!
I'll post the whole working code, so that anyone who has the same problem can use this:

//-----------------------------------------------------------------------------// File: Vertices.cpp//// Desc: In this tutorial, we are rendering some Vertices. This introduces the//       concept of the vertex buffer, a Direct3D object used to store//       Vertices. Vertices can be defined any way we want by defining a//       custom structure and a custom FVF (flexible vertex format). In this//       tutorial, we are using Vertices that are transformed (meaning they//       are already in 2D window coordinates) and lit (meaning we are not//       using Direct3D lighting, but are supplying our own colors).//// Copyright (c) Microsoft Corporation. All rights reserved.//-----------------------------------------------------------------------------#include <d3d9.h>#include <d3dx9.h>#pragma warning( disable : 4996 ) // disable deprecated warning #pragma warning( default : 4996 )#include <stdexcept>#include <gdiplus.h>#include <atlimage.h>#include <strsafe.h>#include <Gdiplusimaging.h>#pragma comment( lib, "gdiplus.lib" )//-----------------------------------------------------------------------------// Global variables//-----------------------------------------------------------------------------LPDIRECT3D9             g_pD3D = NULL; // Used to create the D3DDeviceLPDIRECT3DDEVICE9       g_pd3dDevice = NULL; // Our rendering deviceLPDIRECT3DVERTEXBUFFER9 g_pVB = NULL; // Buffer to hold VerticesLPDIRECT3DVERTEXBUFFER9 g_pVBTQ = NULL; // Buffer to hold Textured Quad verticesLPDIRECT3DTEXTURE9	g_pOORT = NULL; // TODO: Overlay offline render target// GDI+ stuffULONG_PTR			gt;Gdiplus::GdiplusStartupInput	gsi;void				*g_pDIBData = NULL;// A structure for our custom vertex typestruct CUSTOMVERTEX{    FLOAT x, y, z, rhw; // The transformed position for the vertex    DWORD color;        // The vertex color};//Custom vertexstruct CUSTOMVERTEX2{    float x, y , z;    float rhw;    DWORD diffuse;    float u, v;};// Our custom FVF, which describes our custom vertex structure#define D3DFVF_CUSTOMVERTEX (D3DFVF_XYZRHW|D3DFVF_DIFFUSE)#define D3DFVF_CUSTOMVERTEX2 (D3DFVF_XYZRHW|D3DFVF_DIFFUSE|D3DFVF_TEX1)//-----------------------------------------------------------------------------// Name: InitD3D()// Desc: Initializes Direct3D//-----------------------------------------------------------------------------HRESULT InitD3D( HWND hWnd ){    // Create the D3D object.    if( NULL == ( g_pD3D = Direct3DCreate9( D3D_SDK_VERSION ) ) )        return E_FAIL;    // Set up the structure used to create the D3DDevice    D3DPRESENT_PARAMETERS d3dpp;    ZeroMemory( &d3dpp, sizeof( d3dpp ) );    d3dpp.Windowed = TRUE;    d3dpp.SwapEffect = D3DSWAPEFFECT_DISCARD;    d3dpp.BackBufferFormat = D3DFMT_UNKNOWN;    // Create the D3DDevice    if( FAILED( g_pD3D->CreateDevice( D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, hWnd,                                      D3DCREATE_SOFTWARE_VERTEXPROCESSING,                                      &d3dpp, &g_pd3dDevice ) ) )    {        return E_FAIL;    }	// Device state would normally be set here	g_pd3dDevice->SetRenderState( D3DRS_LIGHTING, FALSE );	g_pd3dDevice->SetRenderState(D3DRS_ALPHABLENDENABLE, TRUE);	g_pd3dDevice->SetRenderState(D3DRS_SRCBLEND, D3DBLEND_SRCALPHA);	g_pd3dDevice->SetRenderState(D3DRS_DESTBLEND, D3DBLEND_INVSRCALPHA);    return S_OK;}//-----------------------------------------------------------------------------// Name: InitVB()// Desc: Creates a vertex buffer and fills it with our Vertices. The vertex//       buffer is basically just a chuck of memory that holds Vertices. After//       creating it, we must Lock()/Unlock() it to fill it. For indices, D3D//       also uses index buffers. The special thing about vertex and index//       buffers is that they can be created in device memory, allowing some//       cards to process them in hardware, resulting in a dramatic//       performance gain.//-----------------------------------------------------------------------------HRESULT InitVB(){    // Initialize three Vertices for rendering a triangle    CUSTOMVERTEX Vertices[] =    {        { 300.0f,  50.0f, 0.5f, 1.0f, 0xffff0000, }, // x, y, z, rhw, color        { 400.0f, 250.0f, 0.5f, 1.0f, 0xff00ff00, },        {  200.0f, 250.0f, 0.5f, 1.0f, 0xff00ffff, },    };    CUSTOMVERTEX2 Vertices2[] =    {	{0, 0, 0, 1.0f, 0x00ffffff, 0, 0 },	//x, y, z, rhw, colour, u, v	{256.0f, 0, 0, 1.0f, 0x00ffffff, 1.0f, 0 },	{256.0f, 256.0f, 0, 1.0f, 0x00ffffff, 1.0f, 1.0f },	{0, 256.0f, 0, 1.0f, 0x00ffffff, 0, 1.0f }    };    // Create the vertex buffer. Here we are allocating enough memory    // (from the default pool) to hold all our 3 custom Vertices. We also    // specify the FVF, so the vertex buffer knows what data it contains.    if( FAILED( g_pd3dDevice->CreateVertexBuffer(3 * sizeof( CUSTOMVERTEX ),						D3DUSAGE_WRITEONLY, //TODO: Fixes D3D warning						D3DFVF_CUSTOMVERTEX,						D3DPOOL_DEFAULT,						&g_pVB,						NULL ) ) )    {        return E_FAIL;    }	if( FAILED( g_pd3dDevice->CreateVertexBuffer(4 * sizeof( CUSTOMVERTEX2 ),                                                     D3DUSAGE_WRITEONLY, //TODO: Fixes D3D warning						     D3DFVF_CUSTOMVERTEX2,						     D3DPOOL_DEFAULT,					             &g_pVBTQ,						     NULL ) ) )    {        return E_FAIL;    }    // Now we fill the vertex buffer. To do this, we need to Lock() the VB to    // gain access to the Vertices. This mechanism is required becuase vertex    // buffers may be in device memory.    VOID* pVertices;    if( FAILED( g_pVB->Lock( 0, sizeof( Vertices ), ( void** )&pVertices, 0 ) ) )        return E_FAIL;		memcpy( pVertices, Vertices, sizeof( Vertices ) );    g_pVB->Unlock();	VOID* pVertices2;    if( FAILED( g_pVBTQ->Lock( 0, sizeof( Vertices2 ), ( void** )&pVertices2, 0 ) ) )        return E_FAIL;		memcpy( pVertices2, Vertices2, sizeof( Vertices2 ) );    g_pVBTQ->Unlock();    return S_OK;}//-----------------------------------------------------------------------------// Name: InitOORT()// Desc: TODO//-----------------------------------------------------------------------------HRESULT InitOORT(){    // Create a blank texture    if( FAILED( g_pd3dDevice->CreateTexture(512,                                             512,					    1,					    D3DUSAGE_DYNAMIC,					    D3DFMT_A8R8G8B8,					    D3DPOOL_DEFAULT,					    &g_pOORT,                                            NULL) ) )    {        return E_FAIL;    }	// GDI+ stuff	GdiplusStartup(>,&gsi,NULL);	return S_OK;}//-----------------------------------------------------------------------------// Name: Cleanup()// Desc: Releases all previously initialized objects//-----------------------------------------------------------------------------VOID Cleanup(){	//GDI resources	Gdiplus::GdiplusShutdown(gt);	//D3D resources        if( g_pVB != NULL )            g_pVB->Release();	if( g_pVBTQ != NULL )           g_pVBTQ->Release();	if ( g_pOORT != NULL )	   g_pOORT->Release();	if( g_pd3dDevice != NULL )           g_pd3dDevice->Release();        if( g_pD3D != NULL )           g_pD3D->Release();    }void RenderOverlays(){	//Lock texture and render	D3DLOCKED_RECT lockedRect;	g_pOORT->LockRect(0, &lockedRect, NULL, 0);		Gdiplus::Bitmap bitmap(512, 512, lockedRect.Pitch, PixelFormat32bppARGB , (BYTE*)lockedRect.pBits);		Gdiplus::Graphics graphics( &bitmap );		graphics.Clear( Gdiplus::Color::Transparent );		Gdiplus::Pen pen( Gdiplus::Color::Red );		graphics.DrawLine(&pen, 10, 10, 120, 120);		::GdiFlush();	g_pOORT->UnlockRect(0);}//-----------------------------------------------------------------------------// Name: Render()// Desc: Draws the scene//-----------------------------------------------------------------------------VOID Render(){    // Clear the backbuffer to a blue color    g_pd3dDevice->Clear( 0, NULL, D3DCLEAR_TARGET, D3DCOLOR_XRGB( 0, 0, 255 ), 1.0f, 0 );    // Render "offline" (outside render loop)    RenderOverlays();    // Begin the scene    if( SUCCEEDED( g_pd3dDevice->BeginScene() ) )    {        // Draw the triangles in the vertex buffer. This is broken into a few        // steps. We are passing the Vertices down a "stream", so first we need        // to specify the source of that stream, which is our vertex buffer. Then        // we need to let D3D know what vertex shader to use. Full, custom vertex        // shaders are an advanced topic, but in most cases the vertex shader is        // just the FVF, so that D3D knows what type of Vertices we are dealing        // with. Finally, we call DrawPrimitive() which does the actual rendering        // of our geometry (in this case, just one triangle).		g_pd3dDevice->SetTexture(0, NULL);        g_pd3dDevice->SetStreamSource( 0, g_pVB, 0, sizeof( CUSTOMVERTEX ) );        g_pd3dDevice->SetFVF( D3DFVF_CUSTOMVERTEX );		g_pd3dDevice->DrawPrimitive( D3DPT_TRIANGLELIST, 0, 1 );		// Set the texture on stage 0		g_pd3dDevice->SetTexture(0, g_pOORT);		// Render a screen space quad		g_pd3dDevice->SetStreamSource( 0, g_pVBTQ, 0, sizeof(CUSTOMVERTEX2) );		g_pd3dDevice->SetFVF( D3DFVF_CUSTOMVERTEX2 );		g_pd3dDevice->DrawPrimitive( D3DPT_TRIANGLEFAN, 0, 2 );        // End the scene        g_pd3dDevice->EndScene();    }    // Present the backbuffer contents to the display    g_pd3dDevice->Present( NULL, NULL, NULL, NULL );}//-----------------------------------------------------------------------------// Name: MsgProc()// Desc: The window's message handler//-----------------------------------------------------------------------------LRESULT WINAPI MsgProc( HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam ){    switch( msg )    {        case WM_DESTROY:            Cleanup();            PostQuitMessage( 0 );            return 0;    }    return DefWindowProc( hWnd, msg, wParam, lParam );}//-----------------------------------------------------------------------------// Name: wWinMain()// Desc: The application's entry point//-----------------------------------------------------------------------------INT WINAPI wWinMain( HINSTANCE hInst, HINSTANCE, LPWSTR, INT ){    // Register the window class    WNDCLASSEX wc =    {        sizeof( WNDCLASSEX ), CS_CLASSDC, MsgProc, 0L, 0L,        GetModuleHandle( NULL ), NULL, NULL, NULL, NULL,        L"D3D Tutorial", NULL    };    RegisterClassEx( &wc );    // Create the application's window    HWND hWnd = CreateWindow( L"D3D Tutorial", L"D3D Tutorial 02: Vertices",                              WS_OVERLAPPEDWINDOW, 128, 128, 512, 512,                              NULL, NULL, wc.hInstance, NULL );    // Initialize Direct3D    if( SUCCEEDED( InitD3D( hWnd ) ) )    {        // Create the vertex buffer and texture         if( SUCCEEDED(InitVB()) && SUCCEEDED(InitOORT()) ) //TODO        {            // Show the window            ShowWindow( hWnd, SW_SHOWDEFAULT );            UpdateWindow( hWnd );            // Enter the message loop            MSG msg;            ZeroMemory( &msg, sizeof( msg ) );            while( msg.message != WM_QUIT )            {                if( PeekMessage( &msg, NULL, 0U, 0U, PM_REMOVE ) )                {                    TranslateMessage( &msg );                    DispatchMessage( &msg );                }                else                    Render();            }        }    }	DestroyWindow(hWnd);    UnregisterClass( L"D3D Tutorial", wc.hInstance );    return 0;}

This is an altered version of the "Vertices.cpp" from the D3DSamples, Tutorial 02. Grab that sample from the SDK and replace Vertices.cpp's contents with what I pasted above.

As a final remark, this is just example code, to see how this works. Needless to say, when I add this functionality to my app, I won't use global variables, I'll respect OOP practices, encapsulate everything, etc. Hope that anyone who uses this code does the same, for the sake of anyone who will mantain his/her code in the future...

This topic is closed to new replies.

Advertisement