XNA for C#
DirectX 9 for C#
DirectX 9 for C++
DirectX 9 for VB
Forum
   
My XNA Book
      
       Go to section on this site

Additional info


Latest Forum posts

 Account settings
  Posted by: Anonymous
  When: 07/05/2014 at 09:48:39

 forced subtitle
  Posted by: Applefly
  When: 07/05/2014 at 06:00:48

 convert DVD into PMS
  Posted by: Applefly
  When: 07/05/2014 at 05:55:25

 DVD to Digital Copy easily
  Posted by: VIKIVannessa
  When: 05/05/2014 at 06:52:29

 DVD on Xbox 360/Xbox One Console
  Posted by: VIKIVannessa
  When: 05/05/2014 at 06:51:47

 Extract .Srt Subtitles
  Posted by: Applefly
  When: 04/05/2014 at 03:54:38

 Encode Movie collection
  Posted by: Applefly
  When: 04/05/2014 at 03:52:41

 Convert DVD to WMV
  Posted by: Applefly
  When: 29/04/2014 at 05:53:50

 rip DVDs into digital files
  Posted by: Applefly
  When: 29/04/2014 at 05:51:20

 iTunes movies/music to Kindle Fire
  Posted by: ciciyu80
  When: 29/04/2014 at 05:10:20


Ads

Rotating your terrain using DirectInput

We’ve already seen how to create a landscape and how to rotate our scene, so now let’s combine them. This chapter we’re going to read keyboard input. Because of this, you can start by completely emptying the OurWindowProcedure method, because we’re also going to end the game loop through DirectInput.

 LRESULT CALLBACK OurWindowProcedure(HWND han_Wind,UINT uint_Message,WPARAM parameter1,LPARAM parameter2)
     return DefWindowProc(han_Wind,uint_Message,parameter1,parameter2);
 }

Now we’re going to link our keyboard to a DirectX device, almost the same way as we did with our graphics card. So we’re going to create a InitializeKeyboard method, that returns a LPDIRECTINPUTDEVICE8, which is a pointer to our keyboard device:

 LPDIRECTINPUTDEVICE8 InitializeKeyboard(HWND han_Window)
 {
     return NULL;
 }

If we want this to run, we’ll first need to add this line to our include block at the top of our code:


#include<dinput.h>
Almost identical to setting up a graphics device, we first need to set up an Object, and have that Object load our Device. So already define pointers to both structures:

 LPDIRECTINPUT8 p_dx_KeybObject;
 LPDIRECTINPUTDEVICE8 p_dx_KeybDevice;
 
 DirectInput8Create(GetModuleHandle(NULL), DIRECTINPUT_VERSION, IID_IDirectInput8, (void**)&p_dx_KeybObject, NULL);

The last line actually creates the DirectInput Object. You need to pass a handle to the current application, the DirectX version, an interface ID, the pointer to the stucture we want to be initialised, and a pointer that can be used for more advanced stuff. When you compile this, however, you should get errormessages like ‘unresolved external symbol _DirectInput8Create’ and ‘unresolved external symbol _IID_IDirectInput8A’. This is again because we have include the header file, but not yet linked to the right .lib files. To do this, find at the bottom of the Project menu, the project’s properties. There, under Configuration Parameters, choose Linker and then Input. Add “dinput8.lib dxguid.lib” to the top line. This should do the trick.

Now your IDE has been set up to use DirectInput, let’s create the keyboard device. This must be done by the CreateDevice method of your keyboard Object:

 p_dx_KeybObject->CreateDevice(GUID_SysKeyboard, &p_dx_KeybDevice, NULL);

First you indicate we’re talking about a keyboard here. Another possiblity could be GUID_SysMouse for example, which would refer to the system’s default mouse. Then we pass the pointer to where our device should be initialized and the last pointer is again only used for advanced stuff, not even DirectX related.

With the keyboard Device created, let’s call the next few methods that configure it:

 p_dx_KeybDevice->SetDataFormat(&c_dfDIKeyboard);
 p_dx_KeybDevice->SetCooperativeLevel(han_Window, DISCL_FOREGROUND|DISCL_NONEXCLUSIVE);
 p_dx_KeybDevice->Acquire();

The first line tells DirectX to have the keyboard send its data in the default format for keyboards, which comes down to a series of bits, with a 1 when a key is pressed and a 0 when it’s not. The next line binds the keyboard device to our window, and the device should only listen to keypressen when the window is active (=in the foreground). Nonexclusive means that other applications may also read the keyboard, even when our window is active. Don’t forget to acquire the keyboard, which gives your application access to the keyboard.

Now return the pointer to our keyboard device:

 return p_dx_KeybDevice;

Of course we have to call this method from the WinMain method as well:

 LPDIRECTINPUTDEVICE8 p_KeybDevice = InitializeKeyboard(han_Window);

Which creates the device, configures it and stores a pointer to it in the local variable p_KeybDevice. Remember the goal of this chapter was to rotate the terrain using the keyboard. Again we have to set up a global variable which will hold the current rotation angle, so declare this at the top of your file:

 float flt_Angle = 0;

With our keyboard device set up, we’re ready to read it every iteration of our game loop. So immediately before your call to DrawScene, put a call to a method we’re going to define now:

 ReadKeyboard(p_KeybDevice);

As you can see, this method of course needs a pointer to our keyboard device.

 void ReadKeyboard(LPDIRECTINPUTDEVICE8 p_Keyb)
 {
 }

The method will simply read the state of the keyboard, which is a series of bytes that indicate which buttons have been pressed since the previous read of the keyboard state. So first define a buffer to hold these bytes and then store the keyboard state in it:

 char chr_KeybState[256];
 p_Keyb->GetDeviceState(sizeof(chr_KeybState),(LPVOID)&chr_KeybState);

The parameters are of course the size of our prepared buffer and the pointer to this buffer. The standard data format of a keyboard corresponds to an array of 256 bytes, and the size of a char is the same as the size of a byte, 8 bits. This is why an array of chars is used.

Now a bit of a detailed part, that I have included only to be complete. If it’s more than you want to know, just skip to the code. For every key, 1 byte is reserved in our buffer. When a key is pressed and the keyboard state is put into our buffer, only the first bit of the byte corresponding to that key will be turned to ‘1’, the other 7 bits of that byte are not affected. So what we’re interested in, is only the first bit. One way to separate this bit from the rest, is to divide the number by 128 (=2^7). So if the result of this division is 1, the key has been pressed.

 if (chr_KeybState[DIK_ESCAPE]/128)
 {
     int_AppRunning = 0;
 }

DIK_ESCAPE is simply a constant defined in the dinput.h file, and indicates the byte in our buffer corresponding to the escape key. So when you run this code, the application should exit when you press the escape key of your keyboard.

With all we’ve seen yet, it’s fairly easy from now to make the keyboard rotate by some keypresses. First check for these keypresses:

 if (chr_KeybState[DIK_DELETE]/128)
 {
     flt_Angle += (float)0.03;
 }
 
 if (chr_KeybState[DIK_NEXT]/128)
 {
     flt_Angle -= (float)0.03;
 }

Thus pressing the page-up and page-down keys of your keyboard will change our global variable. Now all we have to do is to replace the code that translates our terrain with this code:

 D3DXMATRIX m_Rotation;
 D3DXMatrixRotationZ(&m_Rotation, flt_Angle);
 D3DXMATRIX m_Translation;
 D3DXMatrixTranslation(&m_Translation,32,-32,0);
 
 D3DXMATRIX m_World;
 D3DXMatrixMultiply(&m_World, &m_Translation, &m_Rotation);
 p_dx_Device->SetTransform(D3DTS_WORLD, &m_World);

Running this should execute an application that reads from the keyboard using DirectInput, opens a file and displays its values using Direct3D, as shown in this image:




DirectX Tutorial 12 - DirectInput

If you appreciate the amount of time I spend creating and updating
these pages, feel free to donate -- any amount is welcome !



Click here to go to the forum on this chapter!

Or click on one of the topics on this chapter to go there:
  • integer to float conversion
          Hi, i can compile it correctly except 3 little thi...
  • problem with DirectInput
          when my window gets out of focus then it does what...
  • C++ Direct3D Mouse Input
          How can I check to see if the Left Mouse Button is...
  • Linker error
          I've set lib path as well as include path, and fo...
  • Tutorial 13: Importing .bmp files
          Post your questions about tutorial 13 here.
  • config error
          hello i didn't know where to put it but here we g...
  • directinput error
          hi I worked my way through the C++ tutorials an...



    Here’s the code:


    #include<windows.h>
    #include<d3d9.h>
    #include<d3dx9.h>
    #include<dinput.h>
    #include<fstream>
    #define WIDTH    64
    #define HEIGHT    64

    struct OURCUSTOMVERTEX
    {
        float x,y,z;
        DWORD color;
    };

    int int_AppRunning = 1;

     float flt_Angle = 0;
     
     LRESULT CALLBACK OurWindowProcedure(HWND han_Wind,UINT uint_Message,WPARAM parameter1,LPARAM parameter2)
     {
         return DefWindowProc(han_Wind,uint_Message,parameter1,parameter2);
     }
     
     HWND NewWindow(LPCTSTR str_Title,int int_XPos, int int_YPos, int int_Width, int int_Height)
     {
         WNDCLASSEX wnd_Structure;
     
         wnd_Structure.cbSize = sizeof(WNDCLASSEX);
         wnd_Structure.style = CS_HREDRAW | CS_VREDRAW;
         wnd_Structure.lpfnWndProc = OurWindowProcedure;
         wnd_Structure.cbClsExtra = 0;
         wnd_Structure.cbWndExtra = 0;
         wnd_Structure.hInstance = GetModuleHandle(NULL);
         wnd_Structure.hIcon = NULL;
         wnd_Structure.hCursor = NULL;
         wnd_Structure.hbrBackground = GetSysColorBrush(COLOR_BTNFACE);
         wnd_Structure.lpszMenuName = NULL;
         wnd_Structure.lpszClassName = "WindowClassName";
         wnd_Structure.hIconSm = LoadIcon(NULL,IDI_APPLICATION);
     
         RegisterClassEx(&wnd_Structure);
     
         return CreateWindowEx(WS_EX_CONTROLPARENT, "WindowClassName", str_Title, WS_OVERLAPPED | WS_CAPTION | WS_SYSMENU | WS_MINIMIZEBOX | WS_VISIBLE, int_XPos, int_YPos, int_Width, int_Height, NULL, NULL, GetModuleHandle(NULL), NULL);
     }
     
     LPDIRECT3DDEVICE9 InitializeDevice(HWND han_WindowToBindTo)
     {
         LPDIRECT3D9 p_dx_Object;
         LPDIRECT3DDEVICE9 p_dx_Device;
     
         p_dx_Object = Direct3DCreate9(D3D_SDK_VERSION);
         if (p_dx_Object == NULL)
         {
             MessageBox(han_WindowToBindTo,"DirectX Runtime library not installed!","InitializeDevice()",MB_OK);
         }
     
         D3DPRESENT_PARAMETERS dx_PresParams;
         ZeroMemory( &dx_PresParams, sizeof(dx_PresParams) );
         dx_PresParams.Windowed = TRUE;
         dx_PresParams.SwapEffect = D3DSWAPEFFECT_DISCARD;
         dx_PresParams.BackBufferFormat = D3DFMT_UNKNOWN;
     
         if (FAILED(p_dx_Object->CreateDevice(D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, han_WindowToBindTo, D3DCREATE_HARDWARE_VERTEXPROCESSING, &dx_PresParams, &p_dx_Device)))
         {
             if (FAILED(p_dx_Object->CreateDevice(D3DADAPTER_DEFAULT, D3DDEVTYPE_REF, han_WindowToBindTo, D3DCREATE_SOFTWARE_VERTEXPROCESSING, &dx_PresParams, &p_dx_Device)))
             {
                 MessageBox(han_WindowToBindTo,"Failed to create even the reference device!","InitializeDevice()",MB_OK);
             }
      }
     
         p_dx_Device->SetRenderState(D3DRS_CULLMODE, D3DCULL_NONE);
         p_dx_Device->SetRenderState(D3DRS_LIGHTING,false);
         p_dx_Device->SetRenderState(D3DRS_FILLMODE,D3DFILL_WIREFRAME);
     
         return p_dx_Device;
     }
     
     void DrawScene(LPDIRECT3DDEVICE9 p_dx_Device, LPDIRECT3DVERTEXBUFFER9 p_dx_VertexBuffer, LPDIRECT3DINDEXBUFFER9 p_dx_IndexBuffer)
     {
         p_dx_Device->Clear(0, NULL, D3DCLEAR_TARGET, D3DCOLOR_XRGB(0,0,0), 1.0f, 0);
         p_dx_Device->BeginScene();
     
         p_dx_Device->SetStreamSource( 0, p_dx_VertexBuffer, 0, sizeof(OURCUSTOMVERTEX) );
      p_dx_Device->SetFVF(D3DFVF_XYZ|D3DFVF_DIFFUSE);
         p_dx_Device->SetIndices(p_dx_IndexBuffer);
     
         D3DXMATRIX m_Rotation;
         D3DXMatrixRotationZ(&m_Rotation, flt_Angle);
         D3DXMATRIX m_Translation;
         D3DXMatrixTranslation(&m_Translation,32,-32,0);
     
         D3DXMATRIX m_World;
         D3DXMatrixMultiply(&m_World, &m_Translation, &m_Rotation);
         p_dx_Device->SetTransform(D3DTS_WORLD, &m_World);
     
         p_dx_Device->DrawIndexedPrimitive(D3DPT_TRIANGLELIST,0,0,WIDTH*HEIGHT,0,(WIDTH-1)*(HEIGHT-1)*2);
     
         p_dx_Device->EndScene();
         p_dx_Device->Present(NULL, NULL, NULL, NULL);
     }
     
     LPDIRECT3DVERTEXBUFFER9 FillVertices(HWND han_Window, LPDIRECT3DDEVICE9 p_dx_Device)
     {
         LPDIRECT3DVERTEXBUFFER9 p_dx_VertexBuffer;
         OURCUSTOMVERTEX cv_Vertices[WIDTH*HEIGHT];
         std::ifstream f_DataFile;
     
         f_DataFile.open("heightdata.raw", std::ios::binary);
     
         if (f_DataFile.is_open())
         {

            for (int x=0;x< WIDTH;x++)        {

                for (int y=0; y< HEIGHT;y++)            {
                    cv_Vertices[y*WIDTH + x].x = -x;
                    cv_Vertices[y*WIDTH + x].y = y;
                    cv_Vertices[y*WIDTH + x].z = f_DataFile.get()/50;
                    cv_Vertices[y*WIDTH + x].color = 0xffffffff;
                }
            }
        }else{
            MessageBox(han_Window,"HeighData file not found!","FillVertices()",MB_OK);
        }

        f_DataFile.close();

        if (FAILED(p_dx_Device->CreateVertexBuffer(WIDTH*HEIGHT*sizeof(OURCUSTOMVERTEX), 0, D3DFVF_XYZ|D3DFVF_DIFFUSE, D3DPOOL_DEFAULT, &p_dx_VertexBuffer, NULL)))
        {        MessageBox(han_Window,"Error while creating VertexBuffer","FillVertices()",MB_OK);
        }

        VOID* p_Vertices;
        if (FAILED(p_dx_VertexBuffer->Lock(0, WIDTH*HEIGHT*sizeof(OURCUSTOMVERTEX), (void**)&p_Vertices, 0)))
        {
            MessageBox(han_Window,"Error trying to lock","FillVertices()",MB_OK);
        }else{
            memcpy(p_Vertices, cv_Vertices, WIDTH*HEIGHT*sizeof(OURCUSTOMVERTEX));
            p_dx_VertexBuffer->Unlock();
        }

        return p_dx_VertexBuffer;
    }

    LPDIRECT3DINDEXBUFFER9 FillIndices(HWND han_Window, LPDIRECT3DDEVICE9 p_dx_Device)
    {
        LPDIRECT3DINDEXBUFFER9 p_dx_IndexBuffer;
        short s_Indices[(WIDTH-1)*(HEIGHT-1)*6];


        for (int x=0;x< WIDTH-1;x++)    {

            for (int y=0; y< HEIGHT-1;y++)        {
                s_Indices[(x+y*(WIDTH-1))*6+2] = x+y*WIDTH;
                s_Indices[(x+y*(WIDTH-1))*6+1] = (x+1)+y*WIDTH;
                s_Indices[(x+y*(WIDTH-1))*6] = (x+1)+(y+1)*WIDTH;

                s_Indices[(x+y*(WIDTH-1))*6+3] = (x+1)+(y+1)*WIDTH;
                s_Indices[(x+y*(WIDTH-1))*6+4] = x+y*WIDTH;
                s_Indices[(x+y*(WIDTH-1))*6+5] = x+(y+1)*WIDTH;
            }
        }

        if (FAILED(p_dx_Device->CreateIndexBuffer((WIDTH-1)*(HEIGHT-1)*6*sizeof(short),D3DUSAGE_WRITEONLY,D3DFMT_INDEX16,D3DPOOL_MANAGED,&p_dx_IndexBuffer,NULL)))
        {
            MessageBox(han_Window,"Error while creating IndexBuffer","FillIndices()",MB_OK);
        }

        VOID* p_Indices;
        if (FAILED(p_dx_IndexBuffer->Lock(0, (WIDTH-1)*(HEIGHT-1)*6*sizeof(short), (void**)&p_Indices, 0)))
        {
            MessageBox(han_Window,"Error trying to lock","FillIndices()",MB_OK);
        }else{
            memcpy(p_Indices, s_Indices, (WIDTH-1)*(HEIGHT-1)*6*sizeof(short));
            p_dx_IndexBuffer->Unlock();
        }

        return p_dx_IndexBuffer;
    }

    void SetUpCamera(LPDIRECT3DDEVICE9 p_dx_Device)
    {
        D3DXVECTOR3 m_EyePos(-40, 0, 50);
        D3DXVECTOR3 m_TargetPos(-5, 0, 0);
        D3DXVECTOR3 m_UpVector(1, 0, 0);
        D3DXMATRIXA16 m_View;
        D3DXMatrixLookAtLH(&m_View, &m_EyePos, &m_TargetPos, &m_UpVector);
        p_dx_Device->SetTransform(D3DTS_VIEW, &m_View);

        D3DXMATRIX m_Projection;
        D3DXMatrixPerspectiveFovLH(&m_Projection, D3DX_PI/4, 500/500, 1, 100);
        p_dx_Device->SetTransform(D3DTS_PROJECTION, &m_Projection);
    }


     LPDIRECTINPUTDEVICE8 InitializeKeyboard(HWND han_Window)
     {
         LPDIRECTINPUT8 p_dx_KeybObject;
         LPDIRECTINPUTDEVICE8 p_dx_KeybDevice;
     
         DirectInput8Create(GetModuleHandle(NULL), DIRECTINPUT_VERSION, IID_IDirectInput8, (void**)&p_dx_KeybObject, NULL);
         p_dx_KeybObject->CreateDevice(GUID_SysKeyboard, &p_dx_KeybDevice, NULL);
     
         p_dx_KeybDevice->SetDataFormat(&c_dfDIKeyboard);
         p_dx_KeybDevice->SetCooperativeLevel(han_Window, DISCL_FOREGROUND|DISCL_NONEXCLUSIVE);
         p_dx_KeybDevice->Acquire();
     
         return p_dx_KeybDevice;
     }
     
     void ReadKeyboard(LPDIRECTINPUTDEVICE8 p_Keyb)
     {
         char chr_KeybState[256];
         p_Keyb->GetDeviceState(sizeof(chr_KeybState),(LPVOID)&chr_KeybState);
     
         if (chr_KeybState[DIK_ESCAPE]/128)
         {
             int_AppRunning = 0;
         }
     
         if (chr_KeybState[DIK_DELETE]/128)
         {
             flt_Angle += (float)0.03;
         }
     
         if (chr_KeybState[DIK_NEXT]/128)
         {
             flt_Angle -= (float)0.03;
         }
     }
     
     int WINAPI WinMain(HINSTANCE hInstance,HINSTANCE hPreviousInstance,LPSTR lpcmdline,int nCmdShow)
     {
         MSG msg_Message;
     
         HWND han_Window = NewWindow("DirectX C++ Tutorial",100,100,500,500);
         LPDIRECT3DDEVICE9 p_Device = InitializeDevice(han_Window);
         LPDIRECT3DVERTEXBUFFER9 p_dx_VB = FillVertices(han_Window, p_Device);
         LPDIRECT3DINDEXBUFFER9 p_dx_IB = FillIndices(han_Window, p_Device);
         SetUpCamera(p_Device);
     
         LPDIRECTINPUTDEVICE8 p_KeybDevice = InitializeKeyboard(han_Window);
     
         while(int_AppRunning)
         {
             if(PeekMessage(&msg_Message,han_Window,0,0,PM_REMOVE))
             {
                 DispatchMessage(&msg_Message);
             }
             ReadKeyboard(p_KeybDevice);
             DrawScene(p_Device, p_dx_VB, p_dx_IB);
         }
     
         p_KeybDevice->Release();
         p_dx_VB->Release();
         p_dx_IB->Release();
         p_Device->Release();
         DestroyWindow(han_Window);
     
         return 0;
     }
     


    Google
     
    Webwww.riemers.net


    If you appreciate the amount of time I spend creating and updating
    these pages, feel free to donate -- any amount is welcome !



    - Website design & XNA + DirectX code : Riemer Grootjans -
    ©2003 - 2011 Riemer Grootjans
  • Translations

    This site in English
    This site in Korean
    This site in Czech

    Microsoft MVP Award



    2007 - 2011 MVP Award
    DirectX - XNA

    Contents

    News
    Home
    Forum
    XNA 2.0 Recipes Book (8)
    XNA 3.0 Recipes Book (8)
    Downloads
    Extra Reading (3)
    Matrices: geometrical
    Matrix Mathematics
    Homogenous matrices
    Community Projects (1)
    Tutorials (160)
    XNA 4.0 using C# (89)
    DirectX using C# (54)
    DirectX using C++ (15)
    Series 1: Terrain (15)
    Opening a window
    Ending the game loop
    Linking to the Device
    Clearing your window
    Drawing a triangle
    Culling
    Camera
    Rotation - Translation
    Indices
    Terrain creation
    Terrain from file
    DirectInput
    Importing .bmp files
    Adding colors
    DirectX Light basics
    DirectX using VB (2)
    -- Expand all --


    Thank you!

    Support this site --
    any amount is welcome !

    Stay up-to-date

    I don't have the time to keep a News section, so stay informed about the updates by clicking on this RSS file!