Friso
Friso

Reputation: 2428

How can I render multiple windows with DirectX 9 in C?

I've already asked this question at https://gamedev.stackexchange.com/questions/50374/how-can-i-render-multiple-windows-with-directx-9-in-c but I have not yet received an answer.

I'm trying to render multiple windows, using DirectX 9 and swap chains, but even though I create 2 windows, I only see the first one that I've created. My RendererDX9 header is this:

#include <d3d9.h>
#include <Windows.h>
#include <vector>

#include "RAT_Renderer.h"

namespace RAT_ENGINE
{
    class RAT_RendererDX9 : public RAT_Renderer
    {
    public:
        RAT_RendererDX9();
        ~RAT_RendererDX9();

        void Init(RAT_WindowManager* argWMan);
        void CleanUp();

        void ShowWin();


    private:
        LPDIRECT3D9           renderInterface; // Used to create the D3DDevice
        LPDIRECT3DDEVICE9     renderDevice;    // Our rendering device
        LPDIRECT3DSWAPCHAIN9* swapChain;       // Swapchain to make multi-window rendering possible
        WNDCLASSEX wc;

        std::vector<HWND> hwindows;

        void Render(int argI);
    };
}

And my .cpp file is this:

#include "RAT_RendererDX9.h"


static LRESULT CALLBACK MsgProc( HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam );


namespace RAT_ENGINE
{
    RAT_RendererDX9::RAT_RendererDX9() : renderInterface(NULL), renderDevice(NULL)
    {
    }

    RAT_RendererDX9::~RAT_RendererDX9()
    {
    }

    void RAT_RendererDX9::Init(RAT_WindowManager* argWMan)
    {   
        wMan = argWMan;
        // Register the window class
        WNDCLASSEX windowClass =
        {
            sizeof( WNDCLASSEX ), CS_CLASSDC, MsgProc, 0, 0,
            GetModuleHandle( NULL ), NULL, NULL, NULL, NULL,
            "foo", NULL
        };

        wc = windowClass;

        RegisterClassEx( &wc );

        for (int i = 0; i< wMan->getWindows().size(); ++i)
        {
            HWND hWnd = CreateWindow( "foo", argWMan->getWindow(i)->getName().c_str(),
                                    WS_OVERLAPPEDWINDOW, argWMan->getWindow(i)->getX(), argWMan->getWindow(i)->getY(), 
                                    argWMan->getWindow(i)->getWidth(), argWMan->getWindow(i)->getHeight(),
                                    NULL, NULL, wc.hInstance, NULL );
            hwindows.push_back(hWnd);
        }

        // Create the D3D object, which is needed to create the D3DDevice.
        renderInterface = (LPDIRECT3D9)Direct3DCreate9( D3D_SDK_VERSION );

        // Set up the structure used to create the D3DDevice. Most parameters are
        // zeroed out. We set Windowed to TRUE, since we want to do D3D in a
        // window, and then set the SwapEffect to "discard", which is the most
        // efficient method of presenting the back buffer to the display.  And 
        // we request a back buffer format that matches the current desktop display 
        // format.
        D3DPRESENT_PARAMETERS deviceConfig;
        ZeroMemory( &deviceConfig, sizeof( deviceConfig ) );
        deviceConfig.Windowed = TRUE;
        deviceConfig.SwapEffect = D3DSWAPEFFECT_DISCARD;
        deviceConfig.BackBufferFormat = D3DFMT_UNKNOWN;
        deviceConfig.BackBufferHeight = 1024;
        deviceConfig.BackBufferWidth = 768;
        deviceConfig.EnableAutoDepthStencil = TRUE;
        deviceConfig.AutoDepthStencilFormat = D3DFMT_D16;

        // Create the Direct3D device. Here we are using the default adapter (most
        // systems only have one, unless they have multiple graphics hardware cards
        // installed) and requesting the HAL (which is saying we want the hardware
        // device rather than a software one). Software vertex processing is 
        // specified since we know it will work on all cards. On cards that support 
        // hardware vertex processing, though, we would see a big performance gain 
        // by specifying hardware vertex processing.
        renderInterface->CreateDevice( D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, hwindows[0],
                              D3DCREATE_SOFTWARE_VERTEXPROCESSING,
                              &deviceConfig, &renderDevice );

        this->swapChain = new LPDIRECT3DSWAPCHAIN9[wMan->getWindows().size()];
        this->renderDevice->GetSwapChain(0, &swapChain[0]);

        for (int i = 0; i < wMan->getWindows().size(); ++i)
        {
            renderDevice->CreateAdditionalSwapChain(&deviceConfig, &swapChain[i]);  
        }

        renderDevice->SetRenderState(D3DRS_CULLMODE, D3DCULL_CCW); // Set cullmode to counterclockwise culling to save resources
        renderDevice->SetRenderState(D3DRS_AMBIENT, 0xffffffff);   // Turn on ambient lighting
        renderDevice->SetRenderState(D3DRS_ZENABLE, TRUE);         // Turn on the zbuffer
    }

    void RAT_RendererDX9::CleanUp()
    {
        renderDevice->Release();
        renderInterface->Release();
    }

    void RAT_RendererDX9::Render(int argI)
    {
        // Clear the backbuffer to a blue color
        renderDevice->Clear( 0, NULL, D3DCLEAR_TARGET, D3DCOLOR_XRGB( 0, 0, 255 ), 1.0f, 0 );
        LPDIRECT3DSURFACE9 backBuffer = NULL;

        // Set draw target
        this->swapChain[argI]->GetBackBuffer(0, D3DBACKBUFFER_TYPE_MONO, &backBuffer);
        this->renderDevice->SetRenderTarget(0, backBuffer);

        // Begin the scene
        renderDevice->BeginScene();

        // End the scene
        renderDevice->EndScene();
        swapChain[argI]->Present(NULL, NULL, hwindows[argI], NULL, 0);
    }   

    void RAT_RendererDX9::ShowWin()
    {
        for (int i = 0; i < wMan->getWindows().size(); ++i)
        {
            ShowWindow( hwindows[i], SW_SHOWDEFAULT );
            UpdateWindow( hwindows[i] );

            // Enter the message loop
            MSG msg;
            while( GetMessage( &msg, NULL, 0, 0 ) )

            {
                if (PeekMessage( &msg, NULL, 0U, 0U, PM_REMOVE ) )
                {
                TranslateMessage( &msg );
                DispatchMessage( &msg );
                }
                else
                {
                    Render(i);
                }
            }
        }
    }
}

LRESULT CALLBACK MsgProc( HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam )
{
    switch( msg )
    {
        case WM_DESTROY:
            //CleanUp();
            PostQuitMessage( 0 );
            return 0;

        case WM_PAINT:
            //Render();
            ValidateRect( hWnd, NULL );
            return 0;
    }

    return DefWindowProc( hWnd, msg, wParam, lParam );
}

I've made a sample function to make multiple windows:

void RunSample1()
{
    //Create the window manager.
    RAT_ENGINE::RAT_WindowManager* wMan = new RAT_ENGINE::RAT_WindowManager();

    //Create the render manager.
    RAT_ENGINE::RAT_RenderManager* rMan = new RAT_ENGINE::RAT_RenderManager();

    //Create a window.
    //This is currently needed to initialize the render manager and create a renderer.
    wMan->CreateRATWindow("Sample 1 - 1", 10, 20, 640, 480);
    wMan->CreateRATWindow("Sample 1 - 2", 150, 100, 480, 640);

    //Initialize the render manager.
    rMan->Init(wMan);

    //Show the window.
    rMan->getRenderer()->ShowWin();
}

How do I get the multiple windows to work?

Upvotes: 4

Views: 4152

Answers (1)

SridharKritha
SridharKritha

Reputation: 9611

The "Swap Chain" approach you used for rendering the multiple windows is sounds good compare to creating multiple devices for multiple screens.

Have you checked the codesampler tutorial for rendering the multiple windows using swap chain. If not, pls find the below link which has a working sample project for rendering the multiple windows using swap chain. This code is purely windows Directx 9 specific but you could added your wrapper to achieve platform agnostic.

  1. Creating Multiple Devices

  2. Using Swap Chain

http://www.codesampler.com/dx9src/dx9src_1.htm

Upvotes: 5

Related Questions