Click here to Skip to main content
Click here to Skip to main content
Articles » Multimedia » DirectX » General » Downloads
 
Add your own
alternative version

A New Perspective on Viewing

, 6 Oct 2009 CPOL
Simple yet comprehensive viewing code for OpenGL and Direct3D.
// GfxDirect3D.cpp
//
// Implements all the Direct3D graphics functionality for the "NewView" demo
// as declared in Gfx.h.
//
// Copyright (C) 2009 John Hilton
//
// Implements the CGfxDirect3D class which implements the IGfx interface for
// graphics transformations and drawing.
//
// CGfxDirect3D
//      (is a): IGfx      - general graphics interface
//      (has a) m_pImpl->   CGfxDirect3DImpl - helper class for CGfxDirect3D
// CGfxDirect3DImpl
//      (is a): CMyDirect3D    - wraps the creation and initialization of Direct3D

#include "stdafx.h"
#pragma region includes
#include "Gfx.h"
#include "GfxSubclass.h"

// Enable extra D3D debugging in debug builds if using the debug DirectX runtime.  
// This makes D3D objects work well in the debugger watch window, but slows down 
// performance slightly.
#if defined(DEBUG) || defined(_DEBUG)
#ifndef D3D_DEBUG_INFO
#define D3D_DEBUG_INFO
#endif
#endif

// Direct3D includes and libs
#include <d3d9.h>
#include <d3dx9.h>
#include <dxerr9.h>
#pragma comment( lib, "dxerr9.lib" )
#pragma comment( lib, "dxguid.lib" )
#if defined(DEBUG) || defined(_DEBUG)
#pragma comment( lib, "d3dx9d.lib" )
#else
#pragma comment( lib, "d3dx9.lib" )
#endif
#pragma comment( lib, "d3d9.lib" )
#pragma comment( lib, "winmm.lib" )
#pragma comment( lib, "comctl32.lib" )
#pragma endregion

#include "GeneralView.h"

class CMyDirect3D
{
    LPDIRECT3D9         m_pDirect3D;
    LPDIRECT3DDEVICE9   m_pDirect3DDevice;
public:
    CMyDirect3D( HWND hWnd )
        : m_pDirect3D(NULL)
        , m_pDirect3DDevice(NULL)
    {
        // Access Direct3D by creating an IDirect3D9 object
        m_pDirect3D = Direct3DCreate9(D3D_SDK_VERSION);
        ASSERT(m_pDirect3D);

        // Prepare the presentation parameters
        D3DPRESENT_PARAMETERS d3dpp; 
        ZeroMemory( &d3dpp, sizeof(d3dpp) );
        d3dpp.Windowed   = TRUE;
        d3dpp.SwapEffect = D3DSWAPEFFECT_DISCARD;
        d3dpp.EnableAutoDepthStencil = TRUE;
        d3dpp.AutoDepthStencilFormat = D3DFMT_D16;

        // Use the current display mode.
        D3DDISPLAYMODE mode;
        V(S(m_pDirect3D->GetAdapterDisplayMode( D3DADAPTER_DEFAULT, &mode )));
        d3dpp.BackBufferFormat = mode.Format;

        // Create a Direct3D device
        d3dpp.hDeviceWindow = hWnd;
        V(S( m_pDirect3D->CreateDevice( D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, NULL,
                                        0 ? D3DCREATE_SOFTWARE_VERTEXPROCESSING
                                          : D3DCREATE_HARDWARE_VERTEXPROCESSING,
                                        &d3dpp, &m_pDirect3DDevice )));
    }

    ~CMyDirect3D()
    {
        if (m_pDirect3DDevice) m_pDirect3DDevice->Release();
        if (m_pDirect3D) m_pDirect3D->Release();
    }

    IDirect3DDevice9*   pDevice()   { return m_pDirect3DDevice; }
    LPDIRECT3D9         pDirect3D() { return m_pDirect3D; }
};

template< typename T >
class CGfxDirect3DImpl
    : public CGfxSubclass<T>
{
public:
    // types
    struct TMatrixStackItem { D3DXMATRIX m; TMatrixStackItem *pPrev, *pNext; };

    // variables
    typename IGfx<T>::ICallbacks*   m_pCallbacks;
    IGfx<T>*            m_pGfx;
    CMyDirect3D*        m_pMyDirect3D;
    TMatrixStackItem    m_WorldStack;
    TMatrixStackItem*   m_pWorld;
    D3DMATERIAL9        m_Material;

    CGfxDirect3DImpl(typename IGfx<T>::ICallbacks& Callbacks, IGfx<T>& Gfx)
        : m_pCallbacks(&Callbacks)
        , m_pGfx(&Gfx)
        , m_pMyDirect3D(NULL)
        , m_pWorld(&m_WorldStack)
    {
        static const D3DMATERIAL9 mat = {
            // Diffuse ambient specular emmissive
            { 0,0,0,1 }, { 0,0,0,1 }, { 0,0,0,0 }, { 0,0,0,0 }
        };
        m_Material = mat;
        m_WorldStack.pPrev = NULL;
        m_WorldStack.pNext = NULL;
    }

    ~CGfxDirect3DImpl()
    {
        if (m_pMyDirect3D) delete m_pMyDirect3D;
        if (m_hWnd)
            UnsubclassWindow();
        // Find the end of the stack list
        TMatrixStackItem* p = &m_WorldStack;
        while (p->pNext)
            p = p->pNext;
        // Delete in reverse
        while (p->pPrev)
        {
            p = p->pPrev;
            delete p->pNext;
        }
        ASSERT(p == &m_WorldStack);
    }

    IDirect3DDevice9* pD3dDevice()
    {
        ASSERT(m_pMyDirect3D);
        return m_pMyDirect3D->pDevice();
    }

    virtual void /*CWindowImpl*/ OnFinalMessage( HWND hWnd )
    {
        m_pCallbacks->OnFinalMessage( hWnd ); // may delete this
    }

    void Attach( HWND hWnd )
    {
        if (!m_hWnd && hWnd)
        {
            // Create
            VERIFY(SubclassWindow(hWnd));
            m_pMyDirect3D = new CMyDirect3D(hWnd);
            ASSERT(m_pMyDirect3D);

            IDirect3DDevice9* pDev = pD3dDevice();
            V(S(pDev->SetRenderState( D3DRS_CULLMODE, D3DCULL_NONE )));
            V(S(pDev->SetFVF( D3DFVF_XYZ )));
            V(S(pDev->SetRenderState( D3DRS_SHADEMODE, D3DSHADE_FLAT )));
            V(S(pDev->SetRenderState( D3DRS_AMBIENT, D3DCOLOR_RGBA(255,255,255,255) )));

            ClearBackBuffer();
            Invalidate();
        }
        else if (m_hWnd && !hWnd)
        {
            // Destroy
            if (m_pMyDirect3D)
            {
                delete m_pMyDirect3D;
                m_pMyDirect3D = NULL;
            }
            UnsubclassWindow();
        }
        else if (m_hWnd)
        {
            // Change
            UnsubclassWindow();
            SubclassWindow( hWnd );
        }
    }

    LRESULT OnPaint(UINT nMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
    {
        nMsg; wParam; lParam; bHandled;

        //if (!wParam) return 0L;
        IDirect3DDevice9* pDev = pD3dDevice();
        V(S(pDev->BeginScene()));
        m_pCallbacks->OnPaint( *m_pGfx );
        V(S(pDev->EndScene()));
        V(S(pDev->Present( NULL, NULL, m_hWnd, NULL )));
        ClearBackBuffer();
        V(ValidateRect(NULL));
        return 0L;
    }

    void ClearBackBuffer()
    {
        // Clear the back buffer to a dark red color
        V(S(pD3dDevice()->Clear( 0, NULL, D3DCLEAR_TARGET|D3DCLEAR_ZBUFFER, D3DCOLOR_XRGB(80,0,0), 1.0f, 0 )));
    }
    void ConfigureView( T ViewVolume[7], T ViewToWorld[4][3] )
    {
        D3DXMATRIX Projection;
        IDirect3DDevice9* pDev = m_pMyDirect3D->pDevice();
        ConfigureView_Direct3D( ViewVolume, ViewToWorld, Projection, m_WorldStack.m );
        ASSERT( m_pWorld == &m_WorldStack );    // pops should have equalled pushes!!
        m_pWorld = &m_WorldStack;
        
        D3DXMATRIX Projection2;
        D3DXMatrixIdentity( &Projection2 );
        D3DXMatrixPerspectiveFovRH( &Projection2, 45*(float)M_PI/180, ViewVolume[0]/ViewVolume[1], 20, 50 );
        
        pDev->SetTransform( D3DTS_PROJECTION, &Projection );
        static const D3DXMATRIX View(1,0,0,0, 0,1,0,0, 0,0,1,0, 0,0,0,1);
        pDev->SetTransform( D3DTS_VIEW, &View );
        //pDev->SetTransform( D3DTS_WORLD, &World );
    }
    void Draw( DWORD* pItem, int length )
    {
        IDirect3DDevice9* pDev = m_pMyDirect3D->pDevice();

        int count;
        while (length > 0)
            switch (*pItem & 0xff000000)
            {
            case gfxColor:
                m_Material.Ambient.r = ((*pItem>>16)&0xff) / 255.0f;
                m_Material.Ambient.g = ((*pItem>> 8)&0xff) / 255.0f;
                m_Material.Ambient.b = ((*pItem    )&0xff) / 255.0f;
                m_Material.Diffuse.r = ((*pItem>>16)&0xff) / 255.0f;
                m_Material.Diffuse.g = ((*pItem>> 8)&0xff) / 255.0f;
                m_Material.Diffuse.b = ((*pItem    )&0xff) / 255.0f;
                V(S(pDev->SetMaterial( &m_Material )));
                pItem++;
                length--;
                break;
            case gfxTriangleStrip:
                count = *pItem & 0x00000fff;
                ASSERT(count);
                V(S(pDev->DrawPrimitiveUP( D3DPT_TRIANGLESTRIP, count, pItem+1, 3*sizeof(float) )));
                pItem += 1+3*(count+2);
                length -= 1+3*(count+2);
                break;
            default:
                ASSERT(0);
                return;
            }
    }
};

#pragma region CGfxDirect3D

template< typename T >
CGfxDirect3D<T>::CGfxDirect3D(typename IGfx<T>::ICallbacks& Callbacks)
{
    m_pImpl = new CGfxDirect3DImpl<T>(Callbacks, *this);
    ASSERT( m_pImpl );
}

template< typename T >
CGfxDirect3D<T>::~CGfxDirect3D(void)
{
    if (m_pImpl) delete m_pImpl;
}

template< typename T >
HWND CGfxDirect3D<T>::Hwnd()
{
    return m_pImpl ? m_pImpl->m_hWnd : NULL;
}

template< typename T >
void CGfxDirect3D<T>::Attach( HWND hWnd )
{
    m_pImpl->Attach( hWnd );
}

template< typename T >
void CGfxDirect3D<T>::ConfigureView( T ViewVolume[7], T ViewToWorld[4][3] )
{
    if (m_pImpl) m_pImpl->ConfigureView( ViewVolume, ViewToWorld );
}

template< typename T >
void CGfxDirect3D<T>::Push()
{
    typedef CGfxDirect3DImpl<T>::TMatrixStackItem TMatrixStackItem;

    // Use a reference to m_pImpl->m_pWorld
    TMatrixStackItem*& pWorld = m_pImpl->m_pWorld;

    // Ensure there is a next stack element
    TMatrixStackItem* pNext = pWorld->pNext;
    if (!pNext)
    {
        pWorld->pNext = pNext = new TMatrixStackItem;
        ASSERT(pNext);
        pNext->pNext = NULL;
        pNext->pPrev = pWorld;
    }

    // Copy the current world transform
    pNext->m = pWorld->m;

    // update m_pImpl->m_pWorld
    pWorld = pNext;
}

template< typename T >
void CGfxDirect3D<T>::Pop()
{
    ASSERT(m_pImpl->m_pWorld->pPrev);
    if (m_pImpl->m_pWorld->pPrev)
        m_pImpl->m_pWorld = m_pImpl->m_pWorld->pPrev;
}

template< typename T >
void CGfxDirect3D<T>::Rotate( T Angle, T Axis[3] )
{
    ASSERT(0); Angle; Axis;
    // to be completed...
}

template< typename T >
void CGfxDirect3D<T>::Rotate( T Matrix[3][3] )
{
    ASSERT(0); Matrix;
    // to be completed...
}

template< typename T >
void CGfxDirect3D<T>::Translate( T x, T y, T z )
{
    ASSERT(m_pImpl && m_pImpl->m_pWorld);
    D3DXMATRIX& m = m_pImpl->m_pWorld->m;

    for (int iCol=0; iCol<3; iCol++)
        m(3,iCol) += x*m(0,iCol) + y*m(1,iCol) + z*m(2,iCol);
}

template< typename T >
void CGfxDirect3D<T>::Scale( T factor )
{
    ASSERT(m_pImpl && m_pImpl->m_pWorld);
    D3DXMATRIX& m = m_pImpl->m_pWorld->m;

    // Scale the 3x3 portion - last column expected to be [0,0,0,1]
    for (int iRow=0; iRow<3; iRow++)
        for (int iCol=0; iCol<3; iCol++)
            m(iRow,iCol) *= factor;
}

template< typename T >
void CGfxDirect3D<T>::Scale( T xyz[3] )
{
    ASSERT(m_pImpl && m_pImpl->m_pWorld);
    D3DXMATRIX& m = m_pImpl->m_pWorld->m;

    // Scale the 3x3 portion - last column expected to be [0,0,0,1]
    for (int iRow=0; iRow<3; iRow++)
    {
        m(iRow,0) *= xyz[0];
        m(iRow,1) *= xyz[1];
        m(iRow,2) *= xyz[2];
    }
}

template< typename T >
void CGfxDirect3D<T>::Render( DWORD* pItem, int length )
{
    ASSERT(m_pImpl && m_pImpl->m_pMyDirect3D && m_pImpl->m_pWorld);
    IDirect3DDevice9* pDev = m_pImpl->m_pMyDirect3D->pDevice();
    D3DXMATRIX& m = m_pImpl->m_pWorld->m;

    // Place the World transform
    pDev->SetTransform( D3DTS_WORLDMATRIX(0), &m );

    m_pImpl->Draw( pItem, length );
}

// Instantiate the class
template CGfxDirect3D<float>;
#pragma endregion

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)

Share

About the Author

John Hilton
Founder Spatial Freedom
Australia Australia
Software engineer, mechanical engineer, electronics engineer, inventor, manager, entrepreneur, husband, father, friend.
B.Sc. B.E.(Hons) M.Eng.Sc.
Some things I've done
- Invented the Spaceball(R)/1983 and Astroid(R)/2002 3D mice
- Patents: 3D mouse, data compression, acoustic transducer
- Wrote animation software in mid 1980s for TV commercials
- Wrote a basic CAD drawing program in 1980s
- Lived in Boston, Massachusetts for 11 years
- Architected and managed full custom ASIC chip
- Reviewed bionic eye technology for investment purposes
- Product development on CPR aid for heart attacks
- Developed an electronic sports whistle
- Was actually stranded on a deserted Pacific island
- Software: lots - embedded, device driver, applications
Some things I want to do
- Develop more cool hardware/software products
- Solve the 3D mouse software barrier to proliferate 3D mice
- Help bring 3D to the masses
- Help others

| Advertise | Privacy | Mobile
Web02 | 2.8.141022.2 | Last Updated 6 Oct 2009
Article Copyright 2009 by John Hilton
Everything else Copyright © CodeProject, 1999-2014
Terms of Service
Layout: fixed | fluid