JMU
Animation in Direct3D
An Example


Prof. David Bernstein
James Madison University

Computer Science Department
bernstdh@jmu.edu


An Example
directx9examples/animation/cube/cube.cpp
        #include "dxstdafx.h"
#include "resource.h"

/**
 * An application that uses Direct3D to render a cube
 * with textures
 *
 * @author  Prof. David Bernstein, James Madison University
 * @version 1.0
 */

// Globals
LPDIRECT3DVERTEXBUFFER9 vertexBuffer = NULL;
LPDIRECT3DTEXTURE9      texture[6];


float rotateX = 0.0f;
float rotateY = 0.0f;

int   axis    = 0;

// Specify the struct for a vertex
struct CUSTOMVERTEX
{
    float x, y, z;
        float u, v;     // Texture coordinates
};

// Specify the flexible vertex format (FVF) for the struct above
#define D3DFVF_CUSTOMVERTEX (D3DFVF_XYZ | D3DFVF_TEX1)


// Color Definitions
DWORD colorBlue   = 0xFF0000FF;
DWORD colorGold   = 0xFFC2A14D; // JMU Gold
DWORD colorGray   = 0xFFAAAAAA;
DWORD colorGreen  = 0xFF00FF00;
DWORD colorPurple = 0xFF450084; // JMU Purple
DWORD colorRed    = 0xFFFF0000;
DWORD colorYellow = 0xFFFFFF00;

// Create the vertex elements
CUSTOMVERTEX vertices[] =
{
        {-1.0f, 1.0f,-1.0f,  0.0f,  0.0f}, // Front
        { 1.0f, 1.0f,-1.0f,  1.0f,  0.0f},
        {-1.0f,-1.0f,-1.0f,  0.0f,  1.0f},
        { 1.0f,-1.0f,-1.0f,  1.0f,  1.0f},
        
        {-1.0f, 1.0f, 1.0f,  1.0f,  0.0f}, // Back
        {-1.0f,-1.0f, 1.0f,  1.0f,  1.0f},
        { 1.0f, 1.0f, 1.0f,  0.0f,  0.0f},
        { 1.0f,-1.0f, 1.0f,  0.0f,  1.0f},
        
        {-1.0f, 1.0f, 1.0f,  0.0f,  0.0f}, // Top
        { 1.0f, 1.0f, 1.0f,  1.0f,  0.0f},
        {-1.0f, 1.0f,-1.0f,  0.0f,  1.0f},
        { 1.0f, 1.0f,-1.0f,  1.0f,  1.0f},
        
        {-1.0f,-1.0f, 1.0f,  0.0f,  0.0f}, // Bottom
        {-1.0f,-1.0f,-1.0f,  1.0f,  0.0f},
        { 1.0f,-1.0f, 1.0f,  0.0f,  1.0f},
        { 1.0f,-1.0f,-1.0f,  1.0f,  1.0f},

        { 1.0f, 1.0f,-1.0f,  0.0f,  0.0f}, // Right
        { 1.0f, 1.0f, 1.0f,  1.0f,  0.0f},
        { 1.0f,-1.0f,-1.0f,  0.0f,  1.0f},
        { 1.0f,-1.0f, 1.0f,  1.0f,  1.0f},
        
        {-1.0f, 1.0f,-1.0f,  1.0f,  0.0f}, // Left
        {-1.0f,-1.0f,-1.0f,  1.0f,  1.0f},
        {-1.0f, 1.0f, 1.0f,  0.0f,  0.0f},
        {-1.0f,-1.0f, 1.0f,  0.0f,  1.0f}
};



/**
 * The function that is called when the timer "ticks"
 */
void CALLBACK exitFrame(UINT id, void* userContext)
{
        if (axis == 0)
                rotateX += (float)D3DX_PI/100.0f;
        else
                rotateY += (float)D3DX_PI/100.0f;
}



/**
 * Checks to see if a device is acceptable
 *
 * @return false if the device isn't acceptable
 */
bool CALLBACK isDeviceAcceptable(D3DCAPS9* caps, D3DFORMAT adapterFormat, 
                                 D3DFORMAT backBufferFormat, bool windowed, 
                                                                 void* userContext )
{
    // Skip backbuffer formats that don't support alpha blending
    IDirect3D9* d3d = DXUTGetD3DObject(); 
    if( FAILED(d3d->CheckDeviceFormat(caps->AdapterOrdinal, caps->DeviceType,
                    adapterFormat, D3DUSAGE_QUERY_POSTPIXELSHADER_BLENDING, 
                    D3DRTYPE_TEXTURE, backBufferFormat)))
        return false;

    return true;
}



/**
 * The function that is called when a key is pressed/released
 */
void CALLBACK keyPressed(UINT nChar, bool keyDown, bool altDown, 
                                                 void* userContext )
{
}




/**
 * Modify device settings (as needed)
 *
 * Note: This function is called before a device is created
 */
bool CALLBACK modifyDeviceSettings(DXUTDeviceSettings* deviceSettings, 
                                                                   const D3DCAPS9* caps, void* userContext )
{
        // Nothing to change in this case
    return true;
}



/**
 * The function that is called when the mouse is
 * moved or clicked
 */
void CALLBACK mouseEvent(bool leftDown, bool rightDown, bool middleDown,
                                                 bool side1Down, bool side2Down,
                                                 int wheelDelta, int x, int y, void* userContext)
{
        if (leftDown)  
        {
                axis = 0;
        }
        else if (rightDown)
        {
                axis = 1;
        }
}





/**
 *  The function that is called to handle MS-Windows messages
 */
LRESULT CALLBACK MsgProc( HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam, 
                          bool* pbNoFurtherProcessing, void* pUserContext )
{
    return 0;
}




/**
 * The function that is called when a device is created
 *
 * Note: This is where D3DPOOL_MANAGED resources should be created
 */
HRESULT CALLBACK onCreateDevice(IDirect3DDevice9* d3dDevice, 
                                                                const D3DSURFACE_DESC* backBufferSurfaceDesc, 
                                                                void* userContext )
{
        // Create the vertex buffer
        d3dDevice->CreateVertexBuffer(24*sizeof(CUSTOMVERTEX),0,  D3DFVF_CUSTOMVERTEX,
                                  D3DPOOL_DEFAULT, &vertexBuffer, NULL );

        // Declare the source data for the buffer
        VOID* data = NULL;

        // Lock the vertex buffer
    vertexBuffer->Lock( 0, sizeof(vertices), (void**)&data, 0 );

        // Copy the vertices into the buffer
    memcpy(data, vertices, sizeof(vertices));

        // Unlock the vertex buffer
    vertexBuffer->Unlock();

        // Set rendering options
    d3dDevice->SetRenderState(D3DRS_LIGHTING, FALSE);
    d3dDevice->SetRenderState(D3DRS_ZENABLE, TRUE);

        // Use a perspective projection
    D3DXMATRIX projection;
    D3DXMatrixPerspectiveFovLH( &projection, D3DXToRadian( 45.0f ), 
                                640.0f / 480.0f, 0.1f, 100.0f );
    d3dDevice->SetTransform(D3DTS_PROJECTION, &projection);


        ZeroMemory(texture, 6*sizeof(LPDIRECT3DTEXTURE9));

        // Create one texture for each face
    D3DXCreateTextureFromFile(d3dDevice, L"brick.bmp",        &texture[0]);
    D3DXCreateTextureFromFile(d3dDevice, L"brownpaper.bmp",   &texture[1]);
    D3DXCreateTextureFromFile(d3dDevice, L"flagstone.bmp",    &texture[2]);
    D3DXCreateTextureFromFile(d3dDevice, L"frostedglass.bmp", &texture[3]);
    D3DXCreateTextureFromFile(d3dDevice, L"lake.bmp",         &texture[4]);
    D3DXCreateTextureFromFile(d3dDevice, L"oak.bmp",          &texture[5]);

        // Set texture-mapping properties
        d3dDevice->SetSamplerState(0, D3DSAMP_MINFILTER, D3DTEXF_LINEAR);
    d3dDevice->SetSamplerState(0, D3DSAMP_MAGFILTER, D3DTEXF_LINEAR);

        return S_OK;
}





/**
 * The function that is called when the device is destroyed
 *
 * Note: This function should release resources created in the 
 * OnCreateDevice callback
 */
void CALLBACK onDestroyDevice(void* userContext )
{
        if( vertexBuffer != NULL ) vertexBuffer->Release(); 

        for (int i=0; i<6; i++)
        {
                if (texture[i] != NULL) texture[i]->Release();
        }

}



/**
 * The function that is called before the call to the 
 * rendering callback
 */
void CALLBACK onFrameMove(IDirect3DDevice9* d3dDevice, 
                                                  double time, float elapsedTime, 
                                                  void* userContext )
{
}

/**
 * The function that is called when the device is lost
 *
 * Note: This function should release resources created in the 
 * OnResetDevice callback
 */
void CALLBACK onLostDevice(void* userContext)
{
}


/**
 * The function that is called when a device is created
 *
 * Note: This is where D3DPOOL_DEFAULT resources should be created
 */
HRESULT CALLBACK onResetDevice(IDirect3DDevice9* d3dDevice, 
                                const D3DSURFACE_DESC* backBufferSurfaceDesc, 
                                                                void* userContext )
{
    return S_OK;
}



/**
 * The function that is called when the scene needs to be rendered
 */
void CALLBACK paint(IDirect3DDevice9* d3dDevice, 
                                        double time, float elapsedTime, 
                                        void* userContext )
{
    HRESULT hr;

    // Clear the render target and the zbuffer 
    V(d3dDevice->Clear(0, NULL, D3DCLEAR_TARGET | D3DCLEAR_ZBUFFER, 
                           D3DCOLOR_ARGB(0, 0xC2, 0xA1, 0x4D), 1.0f, 0) );


    // Render the scene
    if( SUCCEEDED(d3dDevice->BeginScene()))
    {
                // Transform the model
                D3DXMATRIX rotate, translate, world;

                D3DXMatrixTranslation(&translate, 0.0f, 0.0f, 5.0f );
                D3DXMatrixRotationYawPitchRoll(&rotate, rotateX, rotateY, 0.0f);

                D3DXMatrixMultiply(&world, &rotate, &translate);
                d3dDevice->SetTransform(D3DTS_WORLD, &world );


                // Starting to define the scene
                d3dDevice->BeginScene();

                // Bind the vertex buffer to the device
                d3dDevice->SetStreamSource(0, vertexBuffer, 0, sizeof(CUSTOMVERTEX));

                // Setup the vertex shader
                d3dDevice->SetFVF(D3DFVF_CUSTOMVERTEX);

                // Draw the various shapes (two triangles for each face)
                d3dDevice->SetTexture(0, texture[0]);
                d3dDevice->DrawPrimitive(D3DPT_TRIANGLESTRIP,  0, 2);

                d3dDevice->SetTexture(0, texture[1]);
                d3dDevice->DrawPrimitive(D3DPT_TRIANGLESTRIP,  4, 2);

                d3dDevice->SetTexture(0, texture[2]);
                d3dDevice->DrawPrimitive(D3DPT_TRIANGLESTRIP,  8, 2);

                d3dDevice->SetTexture(0, texture[3]);
                d3dDevice->DrawPrimitive(D3DPT_TRIANGLESTRIP, 12, 2);

                d3dDevice->SetTexture(0, texture[4]);
                d3dDevice->DrawPrimitive(D3DPT_TRIANGLESTRIP, 16, 2);

                d3dDevice->SetTexture(0, texture[5]);
                d3dDevice->DrawPrimitive(D3DPT_TRIANGLESTRIP, 20, 2);

        V(d3dDevice->EndScene());
    }
}



/**
 * The entry-point of the application
 */
INT WINAPI WinMain(HINSTANCE, HINSTANCE, LPSTR, int)
{
    // Register the device-reated callbacks
    DXUTSetCallbackDeviceCreated(onCreateDevice);
    DXUTSetCallbackDeviceReset(onResetDevice);
    DXUTSetCallbackDeviceLost(onLostDevice);
    DXUTSetCallbackDeviceDestroyed(onDestroyDevice);

        // Register message callbacks
    DXUTSetCallbackMsgProc(MsgProc);

        // Register the pre-rendering callback
    DXUTSetCallbackFrameMove(onFrameMove);

        // Register the render/display callback
    DXUTSetCallbackFrameRender(paint);

        // Register the keyboard callback
        DXUTSetCallbackKeyboard(keyPressed);

        // Register the mouse callback
        bool includeMouseMoveEvents = false;
        DXUTSetCallbackMouse(mouseEvent, includeMouseMoveEvents);

        // Register the timer callback
        DXUTSetTimer(exitFrame, 0.025f);

    // Initialize DXUT and create the desired Win32 window
        // and Direct3D device for the application
        //
    DXUTInit(true,  // Parse the command line
             true,  // Handle default hotkeys
                         true); // Show msgboxes

        // Setup the cursor
    DXUTSetCursorSettings(true,   // Show the cursor
                                  true ); // Clip the cursor in full screen mode

        // Create the window
    DXUTCreateWindow(L"Cube"); // Title

        // Create the device/renderer
    DXUTCreateDevice(D3DADAPTER_DEFAULT,    // Adapter
                     true,                  // Windowed
                     640, 480,              // Width, Height
                     isDeviceAcceptable,    // Acceptable Callback
                     modifyDeviceSettings); // Settings Callback

    // Start the render loop
    DXUTMainLoop();


    return DXUTGetExitCode();
}