This tutorial is part of a Collection: 02. DirectX 10 - Braynzar Soft Tutorials
rate up
0
rate down
1498
views
bookmark
16. Direct Input

In this lesson, we will learn how to use Direct Input to get keyboard and mouse information from the user. This is a pretty short lesson that builds off the last lesson, Simple Lighting.

There are no files for this tutorial
Video games without input are not really video games, more like a movie. In this lesson we will learn how to use the Direct Input API. You may wonder why we are not going to use Win32 API to get input from the user, after all, it can find which keys were pressed on the keyboard, get input from the mouse and even from a joystick. Well, the Win32 API was designed as a means for keyboard entry applications, not for speed real time input. When getting input with the Win32 API, it needs to process the keys, convert them to ascii and there is a lot of extra processing for special windows keys pressed like "alt". So much processesing that games don't need, and remember, we can't render a frame until our message queue is empty. It's actually very very slow. Another thing, is the Win32 API can only take input from 3 buttons, x and y axis, and a mouse wheel from a mouse. Many mouses now days have much more function than that. Direct Input can support pretty much any device as long as it has a Direct Input driver written for it, which is pretty much all of them. With Direct Input, We can use a feature called force feedback, thats when a joystick can rumble and get input from the application. So now we know why we should use Direct Input. Lets move on to how we can use it. Here we include the Direct Input header file and libraries. #include <dinput.h> #pragma comment (lib, "dinput8.lib") #pragma comment (lib, "dxguid.lib") Next we initialize a couple variables. The first two are initializing IDirectInputDevice8 COM Interfaces which represent a physical object we can use to get input. The next line initializes a structure which we will use to get the state of our mouse. Then we initialize a structure to get input from our keyboard. After that we have a couple variables we will update as we press keys to change the position and rotation of our cubes. IDirectInputDevice8* DIKeyboard; IDirectInputDevice8* DIMouse; DIMOUSESTATE mouseLastState; LPDIRECTINPUT8 DirectInput; float rotx = 0; float rotz = 0; float moveUD = 0; float moveLR = 0; D3DXMATRIX Rotationx; D3DXMATRIX Rotationz; We call our InitDirectInput() function from our winmain function. We will go over this function in a moment. if(!InitDirectInput(hInstance)) { MessageBox(0, L"Direct Input Initialization - Failed", L"Error", MB_OK); return 0; } Now we go down to where we have a new function called InitDirectInput(). This function will initialize direct input, just like we have a function to initialize direct3d. The first line here creates our Direct Input object, much like we created our Direct3d object. We can create a Direct Input object be calling the function DirectInput8Create(). See how it says DirectInput8? That is because Direct Input has not been updated since version 8 in 2000. It is the same since the version that shipped out with directx 8. Its a good API that has not needed updating. Here is the parameters for DirectInput8Create() HRESULT WINAPI DirectInput8Create( HINSTANCE hinst, DWORD dwVersion, REFIID riidltf, LPVOID *ppvOut, LPUNKNOWN punkOuter ); **hinst** - This is the handle to the instance of our application. **dwVersion** - This is the version of the direct input we want to use, specify DIRECTINPUT_VERSION. **riidltf** - This is an identifier to the interface of direct input we want to use, specify IID_IDirectInput8. **ppvOut** - This is the returned pointer to our direct input object. **punkOuter** - This is used for COM aggregation, specify NULL bool InitDirectInput(HINSTANCE hInstance) { DirectInput8Create(hInstance, DIRECTINPUT_VERSION, IID_IDirectInput8, (void**)&DirectInput, NULL); Next we create our keyboard object using the CreateDevice() function of our direct input object. The first parameter we enter the flag for the GUID (Globally Unique Identifiers) device we want to use, we enter GUID_SysKeyboard, we don't have to worry about picking the right one as there is only one keyboard. Then we return a pointer to the created device, thats what the second parameter is. The third parameter is COM related, we don't need to worry about it so set it to NULL. Then we do the same thing for our mouse, but use GUID_SysMouse (our default mouse) and return the pointer to our DIMouse object. DirectInput->CreateDevice(GUID_SysKeyboard, &DIKeyboard, NULL); DirectInput->CreateDevice(GUID_SysMouse, &DIMouse, NULL); Direct Input lets us tell the device what kind of input we are expecting. For example, if we have a joystick, we might need to tell it we are expecting the joystick to rotate around an axis, and if we have a mouse, we need to tell the mouse we are expecting it to rotate freely. We can do this with the following: HRESULT IDirectInputDevice8::SetDataFormat( LPCDIDATAFORMAT lpdf ); lpdf is a pointer to a DIDATAFORMAT object, which can be one of the following: **c_dfDIKeyboard** Standard keyboard structure. An array of 256 characters, one for each key. **c_dfDIMouse** Standard mouse structure. Three axes and four buttons. Corresponds to the DIMOUSESTATE structure. **c_dfDIMouse2** Extended mouse structure. Three axes and eight buttons. Corresponds to the DIMOUSESTATE2 structure. **c_dfDIJoystick** Standard joystick. Three positional axes, three rotation axes, two sliders, a POV hat, and 32 buttons. Corresponds to the DIJOYSTATE structure. **c_dfDIJoystick2** Extended capability joystick. Refer to the SDK documentation for the truly massive data format definition. Corresponds to the DIJOYSTATE2 structure. And that concludes our InitDirectInput() function. DIKeyboard->SetDataFormat(&c_dfDIKeyboard); DIKeyboard->SetCooperativeLevel(hwnd, DISCL_FOREGROUND | DISCL_NONEXCLUSIVE); DIMouse->SetDataFormat(&c_dfDIMouse); DIMouse->SetCooperativeLevel(hwnd, DISCL_EXCLUSIVE | DISCL_NOWINKEY | DISCL_FOREGROUND); return true; } Next up we have our DetectInput() function. In this function we will be detecting if a key was pressed or if the mouse has moved. Then we take action accordingly. First we initialize a DIMOUSESTATE type which we will talk about in a moment. Then we make a variable of type BYTE to hold an array of the possible keyboard keys to be pressed. Sometimes when running an application, another application takes over the keyboard, mouse, or joystick device, preventing the current application to use it. To fix this problem, we use the Acquire() function, to take back over the device. A lot of times you will see this function scattered around a program to make sure the program has control over the device. void DetectInput() { DIMOUSESTATE mouseCurrState; BYTE keyboardState[256]; DIKeyboard->Acquire(); DIMouse->Acquire(); What this first function does is get the state of our device. Since we have specified c_dfDIMouse as a device, we need to fill in the first parameter with the size of the DIMOUSESTATE structure. Then it sends a pointer of our device's state. The DIMOUSESTATE holds the buttons and axis our mouse might use, the structure looks like this: typedef struct DIMOUSESTATE { LONG lX; LONG lY; LONG lZ; BYTE rgbButtons[4]; } DIMOUSESTATE, *LPDIMOUSESTATE; Where the first three are the x, y, and z axis of our mouse, and the last one is the possible 4 buttons (use DIMOUSESTATE2 for more buttons). x and y are used for moving the mouse around, and the z is the mouse wheel. The x, y and z axis will return 0 if they have not moved since the last time it was checked. After that we check the device state of our keyboard. The first parameter is an array of 256 chars to hold the constants for each key, and the second is the returned state (pressed key). DIMouse->GetDeviceState(sizeof(DIMOUSESTATE), &mouseCurrState); DIKeyboard->GetDeviceState(sizeof(keyboardState),(LPVOID)&keyboardState); Now we do our input checking. The check keyboard state will return the 256 char array, and we can check the array to see if a certain button was pressed. Its an array of const chars, and the following are some common ones we can check for, you can find more if you need: **DIK_A** ... DIK_Z A through Z **DIK_0** ... DIK_9 0 through 9 **DIK_F1** ... DIK_F15 F1 through F15 **DIK_NUMPAD0** ... DIK_NUMPAD9 0 through 9 on the numpad. The keys are the same whether or not num lock is turned on. **DIK_ESCAPE** Escape key **DIK_SPACE** Spacebar **DIK_RETURN** Return or Enter key **DIK_NUMPADENTER** Enter key on numpad **DIK_UP** Up arrow key **DIK_DOWN** Down arrow key **DIK_LEFT** Left arrow key **DIK_RIGHT** Right arrow key **DIK_SUBTRACT** - key on keypad **DIK_ADD** + key on keypad **DIK_MINUS** - key next to the equals key on top row **DIK_EQUALS** = key next to backspace **DIK_BACK** backspace key **DIK_TAB** Tab key **DIK_LCONTROL** >left side Ctrl key **DIK_LSHIFT** Left Shift key **DIK_RSHIFT** Right side Shift key **DIK_LMENU** Alt key on the left **DIK_RMENU** Alt key on the right **DIK_RCONTROL** Right side control key **DIK_LWIN** Left side windows key After we check for the keys we want from the keyboard, we need to see if the mouse has moved. Remember before we initialized mouseLastState? That will hold the current state at the end of this function, and when the function gets called again, the actual current mouse state will be reset, and if it is different from the old mouse state, then we know the mouse has moved or a button has been pressed. We first check the x axis, then we check the y axis. Then we set the variables which we will use to move our center cube up, down, left and right. After all that, we check to make sure our variables do not get too high or low from running the program for too long, then we are done with this function. if(keyboardState[DIK_ESCAPE] & 0x80) PostMessage(hwnd, WM_DESTROY, 0, 0); if(keyboardState[DIK_LEFT] & 0x80) { rotz -= 0.0005f; } if(keyboardState[DIK_RIGHT] & 0x80) { rotz += 0.0005f; } if(keyboardState[DIK_UP] & 0x80) { rotx += 0.0005f; } if(keyboardState[DIK_DOWN] & 0x80) { rotx -= 0.0005f; } if(mouseCurrState.lX != mouseLastState.lX) { moveLR -= (mouseCurrState.lX * 0.001f); } if(mouseCurrState.lY != mouseLastState.lY) { moveUD += (mouseCurrState.lY * 0.001f); } if ( rotx > (float) 6.283185 ) rotx -= (float)6.283185; else if ( rotx < 0 ) rotx = (float)6.283185 + rotx; if ( rotz > (float)6.283185 ) rotz -= (float)6.283185; else if ( rotz < 0 ) rotz = (float)6.283185 + rotz; mouseLastState = mouseCurrState; return; } Move down to our ReleaseObjects() function, where we unacquire our keyboard and mouse devices, letting other apps use them, and release our DirectInput COM object. DIKeyboard->Unacquire(); DIMouse->Unacquire(); DirectInput->Release(); Theres not much new information to give in our drawscene function, but i wanted you to know everything we did in this lesson. First we make a couple new vectors to hold our rotation in. then we do the rotation for each axis using our variables we will be changing by pressing keys. After we are done with the rotation calculations, we do the translation with the variable we will be changing by moving our mouse around. After that we put them all together in the Transformations matrix, Check to make sure our rot variable is less than 2 pi or greater than zero (we do this to avoid a really large number after running the program for a while), then we draw our objects, which we do not see here. D3DXVECTOR3 rotyaxis(0.0f, 1.0f, 0.0f); D3DXVECTOR3 rotzaxis(0.0f, 0.0f, 1.0f); D3DXVECTOR3 rotxaxis(1.0f, 0.0f, 0.0f); D3DXMatrixRotationAxis(&Rotation, &rotyaxis, rot); D3DXMatrixRotationAxis(&Rotationx, &rotxaxis, rotx); D3DXMatrixRotationAxis(&Rotationz, &rotzaxis, rotz); D3DXMatrixTranslation( &Translation, 0.0f, 0.0f, 4.0f ); Transformations = Translation * Rotation * Rotationx * Rotationz; rot += .0005f; if ( rot > (float)6.283185 ) rot -= (float)6.283185; else if ( rot < 0 ) rot = (float)6.283185 + rot; The last thing we need to do is call the DetectInput function from our message loop. We will call it right before we draw our scene. Also notice i took out the old escape key check using the Win32 API, thats because we now check it using Direct Input ;) int messageloop(){ MSG msg; ZeroMemory(&msg, sizeof(MSG)); while(true) { BOOL PeekMessageL( LPMSG lpMsg, HWND hWnd, UINT wMsgFilterMin, UINT wMsgFilterMax, UINT wRemoveMsg ); if (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) { if (msg.message == WM_QUIT) break; TranslateMessage(&msg); DispatchMessage(&msg); } else{ // run game code DetectInput(); DrawScene(); } } return msg.wParam; } There! That wasn't too bad! Soon we'll learn how to use Direct Input to manipulate a camera and shoot guns! Here's the final code: main.cpp #include <Windows.h> #include <d3d10.h> #include <d3dx10.h> #include <string> ////////////////////new////////////////////////////////////////////////////////////////////// #include <dinput.h> #pragma comment (lib, "dinput8.lib") #pragma comment (lib, "dxguid.lib") ////////////////////new////////////////////////////////////////////////////////////////////// #pragma comment(lib, "D3D10.lib") #pragma comment(lib, "d3dx10d.lib") LPCTSTR WndClassName = L"firstwindow"; HWND hwnd = NULL; const int Width = 800; const int Height = 600; bool InitializeWindow(HINSTANCE hInstance, int ShowWnd, int width, int height, bool windowed); HRESULT hr; ID3D10Device* d3dDevice; IDXGISwapChain* SwapChain; ID3D10RenderTargetView* RenderTargetView; ID3D10Effect* FX; ID3D10InputLayout* VertexLayout; ID3D10Buffer* VertexBuffer; ID3D10Buffer* IndexBuffer; ID3D10EffectTechnique* Technique; ID3D10DepthStencilView* DepthStencilView; ID3D10Texture2D* DepthStencilBuffer; ID3D10ShaderResourceView* DiffuseMapResourceView; ID3D10EffectShaderResourceVariable* fxDiffuseMapVar; ID3D10EffectMatrixVariable* fxWVPVar; D3DXMATRIX WVP; D3DXMATRIX World; D3DXMATRIX View; D3DXMATRIX Projection; D3DXVECTOR3 Position; D3DXVECTOR3 Target; D3DXVECTOR3 Up; ID3D10EffectVariable* fxLightVar; //////////////////////////////new///////////////////////////////////////////////////////// IDirectInputDevice8* DIKeyboard; IDirectInputDevice8* DIMouse; DIMOUSESTATE mouseLastState; LPDIRECTINPUT8 DirectInput; float rotx = 0; float rotz = 0; float moveUD = 0; float moveLR = 0; D3DXMATRIX Rotationx; D3DXMATRIX Rotationz; ////////////////////new////////////////////////////////////////////////////////////////////// D3DXMATRIX Rotation; D3DXMATRIX Scale; D3DXMATRIX Translation; D3DXMATRIX Transformations; float rot = 0.01f; bool InitializeDirect3dApp(HINSTANCE hInstance); bool InitDirectInput(HINSTANCE hInstance); void DetectInput(); bool InitScene(); void DrawScene(); bool ReleaseObjects(); int messageloop(); LRESULT CALLBACK WndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam); struct Vertex { Vertex(){} Vertex(float x, float y, float z, float u, float v, float nx, float ny, float nz) : pos(x,y,z), texCoord(u,v), normal(nx,ny,nz){} D3DXVECTOR3 pos; D3DXVECTOR2 texCoord; D3DXVECTOR3 normal; }; struct Light { Light() { ZeroMemory(this, sizeof(Light)); } D3DXVECTOR3 dir; float pad; D3DXCOLOR ambient; D3DXCOLOR diffuse; }; Light light; int WINAPI WinMain(HINSTANCE hInstance, //Main windows function HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nShowCmd) { if(!InitializeWindow(hInstance, nShowCmd, Width, Height, true)) { MessageBox(0, L"Window Initialization - Failed", L"Error", MB_OK); return 0; } if(!InitializeDirect3dApp(hInstance)) { MessageBox(0, L"Direct3D Initialization - Failed", L"Error", MB_OK); return 0; } if(!InitDirectInput(hInstance)) { MessageBox(0, L"Direct Input Initialization - Failed", L"Error", MB_OK); return 0; } if(!InitScene()) { MessageBox(0, L"Scene Initialization - Failed", L"Error", MB_OK); return 0; } messageloop(); if(!ReleaseObjects()) { MessageBox(0, L"Object Releasing - Failed", L"Error", MB_OK); return 0; } return 0; } bool InitializeWindow(HINSTANCE hInstance, int ShowWnd, int width, int height, bool windowed) { typedef struct _WNDCLASS { UINT cbSize; UINT style; WNDPROC lpfnWndProc; int cbClsExtra; int cbWndExtra; HANDLE hInstance; HICON hIcon; HCURSOR hCursor; HBRUSH hbrBackground; LPCTSTR lpszMenuName; LPCTSTR lpszClassName; } WNDCLASS; WNDCLASSEX wc; wc.cbSize = sizeof(WNDCLASSEX); wc.style = CS_HREDRAW | CS_VREDRAW; wc.lpfnWndProc = WndProc; wc.cbClsExtra = NULL; wc.cbWndExtra = NULL; wc.hInstance = hInstance; wc.hIcon = LoadIcon(NULL, IDI_APPLICATION); wc.hCursor = LoadCursor(NULL, IDC_ARROW); wc.hbrBackground = (HBRUSH)(COLOR_WINDOW + 2); wc.lpszMenuName = NULL; wc.lpszClassName = WndClassName; wc.hIconSm = LoadIcon(NULL, IDI_APPLICATION); if (!RegisterClassEx(&wc)) { MessageBox(NULL, L"Error registering class", L"Error", MB_OK | MB_ICONERROR); return 1; } hwnd = CreateWindowEx( NULL, WndClassName, L"Window Title", WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, CW_USEDEFAULT, width, height, NULL, NULL, hInstance, NULL ); if (!hwnd) { MessageBox(NULL, L"Error creating window", L"Error", MB_OK | MB_ICONERROR); return 1; } ShowWindow(hwnd, ShowWnd); UpdateWindow(hwnd); return true; } bool InitializeDirect3dApp(HINSTANCE hInstance) { UINT createDeviceFlags = 0; D3D10_DRIVER_TYPE driverTypes[] = { D3D10_DRIVER_TYPE_HARDWARE, D3D10_DRIVER_TYPE_REFERENCE, }; UINT numDriverTypes = sizeof( driverTypes ) / sizeof( driverTypes[0] ); DXGI_SWAP_CHAIN_DESC scd; scd.BufferDesc.Width = Width; scd.BufferDesc.Height = Height; scd.BufferDesc.RefreshRate.Numerator = 60; scd.BufferDesc.RefreshRate.Denominator = 1; scd.BufferDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM; scd.BufferDesc.ScanlineOrdering = DXGI_MODE_SCANLINE_ORDER_UNSPECIFIED; scd.BufferDesc.Scaling = DXGI_MODE_SCALING_UNSPECIFIED; //no multisampling scd.SampleDesc.Count = 1; scd.SampleDesc.Quality = 0; scd.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT; scd.BufferCount = 1; scd.OutputWindow = hwnd; scd.Windowed = true; scd.SwapEffect = DXGI_SWAP_EFFECT_DISCARD; scd.Flags = 0; D3D10CreateDeviceAndSwapChain(0, D3D10_DRIVER_TYPE_HARDWARE, 0, 0, D3D10_SDK_VERSION, &scd, &SwapChain, &d3dDevice); ID3D10Texture2D* backBuffer; SwapChain->GetBuffer(0, _uuidof(ID3D10Texture2D), reinterpret_cast<void**>(&backBuffer)); d3dDevice->CreateRenderTargetView(backBuffer, 0, &RenderTargetView); backBuffer->Release(); D3D10_TEXTURE2D_DESC depthStencilDesc; depthStencilDesc.Width = Width; depthStencilDesc.Height = Height; depthStencilDesc.MipLevels = 1; depthStencilDesc.ArraySize = 1; depthStencilDesc.Format = DXGI_FORMAT_D24_UNORM_S8_UINT; depthStencilDesc.SampleDesc.Count = 1; depthStencilDesc.SampleDesc.Quality = 0; depthStencilDesc.Usage = D3D10_USAGE_DEFAULT; depthStencilDesc.BindFlags = D3D10_BIND_DEPTH_STENCIL; depthStencilDesc.CPUAccessFlags = 0; depthStencilDesc.MiscFlags = 0; d3dDevice->CreateTexture2D(&depthStencilDesc, NULL, &DepthStencilBuffer); d3dDevice->CreateDepthStencilView(DepthStencilBuffer, NULL, &DepthStencilView); d3dDevice->OMSetRenderTargets(1, &RenderTargetView, DepthStencilView); // Setup the viewport D3D10_VIEWPORT vp; vp.Width = Width; vp.Height = Height; vp.MinDepth = 0.0f; vp.MaxDepth = 1.0f; vp.TopLeftX = 0; vp.TopLeftY = 0; d3dDevice->RSSetViewports( 1, &vp ); D3DXMatrixIdentity( &World ); Position = D3DXVECTOR3( 0.0f, 6.0f, -14.0f ); Target = D3DXVECTOR3( 0.0f, 0.0f, 0.0f ); Up = D3DXVECTOR3( 0.0f, 1.0f, 0.0f ); D3DXMatrixLookAtLH( &View, &Position, &Target, &Up ); return true; } ////////////////////new////////////////////////////////////////////////////////////////////// bool InitDirectInput(HINSTANCE hInstance) { DirectInput8Create(hInstance, DIRECTINPUT_VERSION, IID_IDirectInput8, (void**)&DirectInput, NULL); DirectInput->CreateDevice(GUID_SysKeyboard, &DIKeyboard, NULL); DirectInput->CreateDevice(GUID_SysMouse, &DIMouse, NULL); DIKeyboard->SetDataFormat(&c_dfDIKeyboard); DIKeyboard->SetCooperativeLevel(hwnd, DISCL_FOREGROUND | DISCL_NONEXCLUSIVE); DIMouse->SetDataFormat(&c_dfDIMouse); DIMouse->SetCooperativeLevel(hwnd, DISCL_EXCLUSIVE | DISCL_NOWINKEY | DISCL_FOREGROUND); return true; } void DetectInput() { DIMOUSESTATE mouseCurrState; BYTE keyboardState[256]; DIKeyboard->Acquire(); DIMouse->Acquire(); DIMouse->GetDeviceState(sizeof(DIMOUSESTATE), &mouseCurrState); DIKeyboard->GetDeviceState(sizeof(keyboardState),(LPVOID)&keyboardState); if(keyboardState[DIK_ESCAPE] & 0x80) PostMessage(hwnd, WM_DESTROY, 0, 0); if(keyboardState[DIK_LEFT] & 0x80) { rotz -= 0.0005f; } if(keyboardState[DIK_RIGHT] & 0x80) { rotz += 0.0005f; } if(keyboardState[DIK_UP] & 0x80) { rotx += 0.0005f; } if(keyboardState[DIK_DOWN] & 0x80) { rotx -= 0.0005f; } if(mouseCurrState.lX != mouseLastState.lX) { moveLR -= (mouseCurrState.lX * 0.001f); } if(mouseCurrState.lY != mouseLastState.lY) { moveUD += (mouseCurrState.lY * 0.001f); } if ( rotx > (float) 6.283185 ) rotx -= (float)6.283185; else if ( rotx < 0 ) rotx = (float)6.283185 + rotx; if ( rotz > (float)6.283185 ) rotz -= (float)6.283185; else if ( rotz < 0 ) rotz = (float)6.283185 + rotz; mouseLastState = mouseCurrState; return; } ////////////////////new////////////////////////////////////////////////////////////////////// bool InitScene() { light.dir = D3DXVECTOR3(0.25f, 0.5f, -1.0f); light.ambient = D3DXCOLOR(0.2f, 0.2f, 0.2f, 1.0f); light.diffuse = D3DXCOLOR(1.0f, 1.0f, 1.0f, 1.0f); Vertex v[24]; // Front Face v[0] = Vertex(-1.0f, -1.0f, -1.0f, 0.0f, 1.0f,-1.0f, -1.0f, -1.0f); v[1] = Vertex(-1.0f, 1.0f, -1.0f, 0.0f, 0.0f,-1.0f, 1.0f, -1.0f); v[2] = Vertex( 1.0f, 1.0f, -1.0f, 1.0f, 0.0f, 1.0f, 1.0f, -1.0f); v[3] = Vertex( 1.0f, -1.0f, -1.0f, 1.0f, 1.0f, 1.0f, -1.0f, -1.0f); // Back Face v[4] = Vertex(-1.0f, -1.0f, 1.0f, 1.0f, 1.0f,-1.0f, -1.0f, 1.0f); v[5] = Vertex( 1.0f, -1.0f, 1.0f, 0.0f, 1.0f, 1.0f, -1.0f, 1.0f); v[6] = Vertex( 1.0f, 1.0f, 1.0f, 0.0f, 0.0f, 1.0f, 1.0f, 1.0f); v[7] = Vertex(-1.0f, 1.0f, 1.0f, 1.0f, 0.0f,-1.0f, 1.0f, 1.0f); // Top Face v[8] = Vertex(-1.0f, 1.0f, -1.0f, 0.0f, 1.0f,-1.0f, 1.0f, -1.0f); v[9] = Vertex(-1.0f, 1.0f, 1.0f, 0.0f, 0.0f,-1.0f, 1.0f, 1.0f); v[10] = Vertex( 1.0f, 1.0f, 1.0f, 1.0f, 0.0f, 1.0f, 1.0f, 1.0f); v[11] = Vertex( 1.0f, 1.0f, -1.0f, 1.0f, 1.0f, 1.0f, 1.0f, -1.0f); // Bottom Face v[12] = Vertex(-1.0f, -1.0f, -1.0f, 1.0f, 1.0f,-1.0f, -1.0f, -1.0f); v[13] = Vertex( 1.0f, -1.0f, -1.0f, 0.0f, 1.0f, 1.0f, -1.0f, -1.0f); v[14] = Vertex( 1.0f, -1.0f, 1.0f, 0.0f, 0.0f, 1.0f, -1.0f, 1.0f); v[15] = Vertex(-1.0f, -1.0f, 1.0f, 1.0f, 0.0f,-1.0f, -1.0f, 1.0f); // Left Face v[16] = Vertex(-1.0f, -1.0f, 1.0f, 0.0f, 1.0f,-1.0f, -1.0f, 1.0f); v[17] = Vertex(-1.0f, 1.0f, 1.0f, 0.0f, 0.0f,-1.0f, 1.0f, 1.0f); v[18] = Vertex(-1.0f, 1.0f, -1.0f, 1.0f, 0.0f,-1.0f, 1.0f, -1.0f); v[19] = Vertex(-1.0f, -1.0f, -1.0f, 1.0f, 1.0f,-1.0f, -1.0f, -1.0f); // Right Face v[20] = Vertex( 1.0f, -1.0f, -1.0f, 0.0f, 1.0f, 1.0f, -1.0f, -1.0f); v[21] = Vertex( 1.0f, 1.0f, -1.0f, 0.0f, 0.0f, 1.0f, 1.0f, -1.0f); v[22] = Vertex( 1.0f, 1.0f, 1.0f, 1.0f, 0.0f, 1.0f, 1.0f, 1.0f); v[23] = Vertex( 1.0f, -1.0f, 1.0f, 1.0f, 1.0f, 1.0f, -1.0f, 1.0f); D3D10_BUFFER_DESC vbd; vbd.Usage = D3D10_USAGE_IMMUTABLE; vbd.ByteWidth = sizeof(Vertex) * 24; vbd.BindFlags = D3D10_BIND_VERTEX_BUFFER; vbd.CPUAccessFlags = 0; vbd.MiscFlags = 0; D3D10_SUBRESOURCE_DATA vinitData; vinitData.pSysMem = v; d3dDevice->CreateBuffer(&vbd, &vinitData, &VertexBuffer); DWORD i[36]; // Front Face i[0] = 0; i[1] = 1; i[2] = 2; i[3] = 0; i[4] = 2; i[5] = 3; // Back Face i[6] = 4; i[7] = 5; i[8] = 6; i[9] = 4; i[10] = 6; i[11] = 7; // Top Face i[12] = 8; i[13] = 9; i[14] = 10; i[15] = 8; i[16] = 10; i[17] = 11; // Bottom Face i[18] = 12; i[19] = 13; i[20] = 14; i[21] = 12; i[22] = 14; i[23] = 15; // Left Face i[24] = 16; i[25] = 17; i[26] = 18; i[27] = 16; i[28] = 18; i[29] = 19; // Right Face i[30] = 20; i[31] = 21; i[32] = 22; i[33] = 20; i[34] = 22; i[35] = 23; D3D10_BUFFER_DESC ibd; ibd.Usage = D3D10_USAGE_IMMUTABLE; ibd.ByteWidth = sizeof(DWORD) * 36; ibd.BindFlags = D3D10_BIND_INDEX_BUFFER; ibd.CPUAccessFlags = 0; ibd.MiscFlags = 0; D3D10_SUBRESOURCE_DATA iinitData; iinitData.pSysMem = i; d3dDevice->CreateBuffer(&ibd, &iinitData, &IndexBuffer); UINT stride = sizeof( Vertex ); UINT offset = 0; d3dDevice->IASetVertexBuffers( 0, 1, &VertexBuffer, &stride, &offset ); d3dDevice->IASetIndexBuffer(IndexBuffer, DXGI_FORMAT_R32_UINT, 0); D3D10_INPUT_ELEMENT_DESC layout[] = { {"POSITION", 0, DXGI_FORMAT_R32G32B32_FLOAT, 0, 0, D3D10_INPUT_PER_VERTEX_DATA, 0 }, {"TEXCOORD", 0, DXGI_FORMAT_R32G32_FLOAT, 0, 12, D3D10_INPUT_PER_VERTEX_DATA, 0}, {"NORMAL", 0, DXGI_FORMAT_R32G32B32_FLOAT, 0, 20, D3D10_INPUT_PER_VERTEX_DATA, 0} }; ID3D10Blob* compilationErrors = 0; HRESULT hr = 0; hr = D3DX10CreateEffectFromFile( L"vertex.fx", NULL, NULL, "fx_4_0", D3D10_SHADER_ENABLE_STRICTNESS, 0, d3dDevice, NULL, NULL, &FX, &compilationErrors, NULL ); if(FAILED(hr)) { MessageBoxA(0, (char*)compilationErrors->GetBufferPointer(), 0, 0); compilationErrors->Release(); return false; } D3DX10CreateShaderResourceViewFromFile(d3dDevice, L"braynzar.jpg", 0, 0, &DiffuseMapResourceView, 0 ); Technique = FX->GetTechniqueByName( "Tech" ); fxWVPVar = FX->GetVariableByName("WVP")->AsMatrix(); fxDiffuseMapVar = FX->GetVariableByName("DiffuseMap")->AsShaderResource(); fxLightVar = FX->GetVariableByName("light"); D3D10_PASS_DESC PassDesc; Technique->GetPassByIndex( 0 )->GetDesc( &PassDesc ); d3dDevice->CreateInputLayout( layout, 3, PassDesc.pIAInputSignature, PassDesc.IAInputSignatureSize, &VertexLayout ); d3dDevice->IASetInputLayout( VertexLayout ); d3dDevice->IASetPrimitiveTopology( D3D10_PRIMITIVE_TOPOLOGY_TRIANGLELIST ); return true; } bool ReleaseObjects() { if( d3dDevice ) d3dDevice->ClearState(); if( VertexBuffer ) VertexBuffer->Release(); if( IndexBuffer ) IndexBuffer->Release(); if( VertexLayout ) VertexLayout->Release(); if( FX ) FX->Release(); if( RenderTargetView ) RenderTargetView->Release(); if( SwapChain ) SwapChain->Release(); if( d3dDevice ) d3dDevice->Release(); if( DiffuseMapResourceView ) DiffuseMapResourceView->Release(); ////////////////////new////////////////////////////////////////////////////////////////////// DIKeyboard->Unacquire(); DIMouse->Unacquire(); DirectInput->Release(); ////////////////////new////////////////////////////////////////////////////////////////////// return true; } void DrawScene() { //Draw Scene Here D3DXCOLOR bgColor( 0.0f, 0.0f, 0.0f, 1.0f); d3dDevice->ClearRenderTargetView( RenderTargetView, bgColor ); d3dDevice->ClearDepthStencilView(DepthStencilView, D3D10_CLEAR_DEPTH|D3D10_CLEAR_STENCIL, 1.0f, 0); D3DXMatrixPerspectiveFovLH(&Projection, 0.4f*3.14f, Width/Height, 1.0f, 1000.0f); ////////////////////new////////////////////////////////////////////////////////////////////// D3DXVECTOR3 rotyaxis(0.0f, 1.0f, 0.0f); D3DXVECTOR3 rotzaxis(0.0f, 0.0f, 1.0f); D3DXVECTOR3 rotxaxis(1.0f, 0.0f, 0.0f); D3DXMatrixRotationAxis(&Rotation, &rotyaxis, rot); D3DXMatrixRotationAxis(&Rotationx, &rotxaxis, rotx); D3DXMatrixRotationAxis(&Rotationz, &rotzaxis, rotz); D3DXMatrixTranslation( &Translation, 0.0f, 0.0f, 4.0f ); Transformations = Translation * Rotation * Rotationx * Rotationz; rot += .0005f; if ( rot > (float)6.283185 ) rot -= (float)6.283185; else if ( rot < 0 ) rot = (float)6.283185 + rot; ////////////////////new////////////////////////////////////////////////////////////////////// WVP = World * Transformations * View * Projection; fxWVPVar->SetMatrix((float*)&WVP); fxDiffuseMapVar->SetResource(DiffuseMapResourceView); fxLightVar->SetRawValue(&light, 0, sizeof(Light)); D3D10_TECHNIQUE_DESC techDesc; Technique->GetDesc( &techDesc ); //draw first cube for( UINT p = 0; p < techDesc.Passes; ++p ) { Technique->GetPassByIndex( p )->Apply( 0 ); d3dDevice->DrawIndexed(36, 0, 0); } D3DXMatrixRotationAxis(&Rotation, &rotyaxis, -rot); D3DXMatrixScaling( &Scale, 1.3f, 1.3f, 1.3f ); D3DXMatrixTranslation( &Translation, moveLR, moveUD, 0.0f ); Transformations = Rotation * Scale * Translation; WVP = World * Transformations * View * Projection; fxWVPVar->SetMatrix((float*)&WVP); //draw second cube for( UINT p = 0; p < techDesc.Passes; ++p ) { Technique->GetPassByIndex( p )->Apply( 0 ); d3dDevice->DrawIndexed(36, 0, 0); } SwapChain->Present( 0, 0 ); } ////////////////////new////////////////////////////////////////////////////////////////////// int messageloop(){ MSG msg; ZeroMemory(&msg, sizeof(MSG)); while(true) { BOOL PeekMessageL( LPMSG lpMsg, HWND hWnd, UINT wMsgFilterMin, UINT wMsgFilterMax, UINT wRemoveMsg ); if (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) { if (msg.message == WM_QUIT) break; TranslateMessage(&msg); DispatchMessage(&msg); } else{ // run game code DetectInput(); DrawScene(); } } return msg.wParam; } ////////////////////new////////////////////////////////////////////////////////////////////// LRESULT CALLBACK WndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) { switch( msg ) { case WM_DESTROY: PostQuitMessage(0); return 0; } return DefWindowProc(hwnd, msg, wParam, lParam); } vertex.fx struct Light { float3 dir; float4 ambient; float4 diffuse; }; cbuffer cbPerFrame { Light light; }; cbuffer cbPerObject { float4x4 WVP; }; Texture2D DiffuseMap; SamplerState TriLinearSample { Filter = MIN_MAG_MIP_LINEAR; }; struct VS_OUTPUT //output structure for vertex shader { float4 Pos : SV_POSITION; float2 texCoord : TEXCOORD; float3 normal : NORMAL; }; // Vertex Shader VS_OUTPUT VS(float4 inPos : POSITION, float2 inTexCoord : TEXCOORD, float3 normal : NORMAL) { VS_OUTPUT output = (VS_OUTPUT)0; output.Pos = mul(inPos, WVP); output.normal = mul(normal, WVP); output.texCoord = inTexCoord; return output; //send color and position to pixel shader } // Pixel Shader float4 PS(VS_OUTPUT input) : SV_Target { input.normal = normalize(input.normal); float4 diffuse = DiffuseMap.Sample( TriLinearSample, input.texCoord ); float3 finalColor; finalColor = diffuse * light.ambient; finalColor += saturate(dot(light.dir, input.normal) * light.diffuse * diffuse); return float4(finalColor, diffuse.a); } technique10 Tech { pass P0 { SetVertexShader( CompileShader( vs_4_0, VS() ) ); SetPixelShader( CompileShader( ps_4_0, PS() ) ); } }