This tutorial is part of a Collection: 03. DirectX 11 - Braynzar Soft Tutorials
rate up
1
rate down
9535
views
bookmark
18. Direct Input

We will learn how to take input from a user, through the keyboard, mouse, or even a joystick in this lesson. We will be learning how to impliment Direct Input in our games!

1275 downloads
##Introduction## 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. ##Headers and Libraries## We need to include and link to the necessary headers and libraries to use direct input. #pragma comment (lib, "dinput8.lib") #pragma comment (lib, "dxguid.lib") #include <dinput.h> ##Global Declarations## 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 scale and rotation of our cubes. IDirectInputDevice8* DIKeyboard; IDirectInputDevice8* DIMouse; DIMOUSESTATE mouseLastState; LPDIRECTINPUT8 DirectInput; float rotx = 0; float rotz = 0; float scaleX = 1.0f; float scaleY = 1.0f; XMMATRIX Rotationx; XMMATRIX Rotationz; ##New Functions## We have two new functions. One to initialized DirectInput, and the other to detect input. The functions which detects input will take a double value representing time, so we are able to keep our scene moving at a constant speed if we want to update some values which will change our scene, which we will. bool InitDirectInput(HINSTANCE hInstance); void DetectInput(double time); ##Init Direct Input from WinMain Function## 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; } ##The InitDirectInput() Function## ( DirectInput8Create() ) 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 by 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) { hr = DirectInput8Create(hInstance, DIRECTINPUT_VERSION, IID_IDirectInput8, (void**)&DirectInput, NULL); ##Create the Direct Input Devices## ( CreateDevice() ) 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. hr = DirectInput->CreateDevice(GUID_SysKeyboard, &DIKeyboard, NULL); hr = DirectInput->CreateDevice(GUID_SysMouse, &DIMouse, NULL); ##Set the Data Format## ( IDirectInputDevice8::SetDataFormat() ) 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.* hr = DIKeyboard->SetDataFormat(&c_dfDIKeyboard); hr = DIKeyboard->SetCooperativeLevel(hwnd, DISCL_FOREGROUND | DISCL_NONEXCLUSIVE); hr = DIMouse->SetDataFormat(&c_dfDIMouse); hr = DIMouse->SetCooperativeLevel(hwnd, DISCL_EXCLUSIVE | DISCL_NOWINKEY | DISCL_FOREGROUND); return true; } ##Detect Input## ( DetectInput() ) 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(double time) { DIMOUSESTATE mouseCurrState; BYTE keyboardState[256]; DIKeyboard->Acquire(); DIMouse->Acquire(); ##Get Current State of Device## 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); ##Check Which Keys Were Pressed## 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 stretch our center cube along the x and y axis. 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. I should mention quickly that Direct Input uses relative mouse coordinates. What this means is it detects how much the mouse has moved since the last time it was checked. Sometimes you might want to get the absolute mouse coordinates, like its exact position on the screen. You can do this by settings its position at the beginning of your scene, then keep track of how much it has moved on the x and y axis. Another way is to use the lparam and wparam in the windows message procedure, which we will do later when we learn how to "pick" an object, or select an object. if(keyboardState[DIK_ESCAPE] & 0x80) PostMessage(hwnd, WM_DESTROY, 0, 0); if(keyboardState[DIK_LEFT] & 0x80) { rotz -= 1.0f * time; } if(keyboardState[DIK_RIGHT] & 0x80) { rotz += 1.0f * time; } if(keyboardState[DIK_UP] & 0x80) { rotx += 1.0f * time; } if(keyboardState[DIK_DOWN] & 0x80) { rotx -= 1.0f * time; } if(mouseCurrState.lX != mouseLastState.lX) { scaleX -= (mouseCurrState.lX * 0.001f); } if(mouseCurrState.lY != mouseLastState.lY) { scaleY -= (mouseCurrState.lY * 0.001f); } if ( rotx > 6.28 ) rotx -= 6.28; else if ( rotx < 0 ) rotx = 6.28 + rotx; if ( rotz > 6.28 ) rotz -= 6.28; else if ( rotz < 0 ) rotz = 6.28 + rotz; mouseLastState = mouseCurrState; return; } ##Clean Up## Don't forget! Also, when we use the mouse and keyboard, we should unaqcuire it so that other applications have access to it. void CleanUp() { //Release the COM Objects we created SwapChain->Release(); d3d11Device->Release(); d3d11DevCon->Release(); renderTargetView->Release(); squareVertBuffer->Release(); squareIndexBuffer->Release(); VS->Release(); PS->Release(); VS_Buffer->Release(); PS_Buffer->Release(); vertLayout->Release(); depthStencilView->Release(); depthStencilBuffer->Release(); cbPerObjectBuffer->Release(); Transparency->Release(); CCWcullMode->Release(); CWcullMode->Release(); d3d101Device->Release(); keyedMutex11->Release(); keyedMutex10->Release(); D2DRenderTarget->Release(); Brush->Release(); BackBuffer11->Release(); sharedTex11->Release(); DWriteFactory->Release(); TextFormat->Release(); d2dTexture->Release(); cbPerFrameBuffer->Release(); ///////////////**************new**************//////////////////// DIKeyboard->Unacquire(); DIMouse->Unacquire(); DirectInput->Release(); ///////////////**************new**************//////////////////// } ##Updating Our Scene## Here we will update our scene depending on the rotx, rotz, scaleX, and scaleY variables which will be updated with user input. void UpdateScene(double time) { //Keep the cubes rotating rot += 1.0f * time; if(rot > 6.28f) rot = 0.0f; //Reset cube1World cube1World = XMMatrixIdentity(); //Define cube1's world space matrix ///////////////**************new**************//////////////////// XMVECTOR rotyaxis = XMVectorSet(0.0f, 1.0f, 0.0f, 0.0f); XMVECTOR rotzaxis = XMVectorSet(0.0f, 0.0f, 1.0f, 0.0f); XMVECTOR rotxaxis = XMVectorSet(1.0f, 0.0f, 0.0f, 0.0f); Rotation = XMMatrixRotationAxis(rotyaxis, rot); Rotationx = XMMatrixRotationAxis(rotxaxis, rotx); Rotationz = XMMatrixRotationAxis(rotzaxis, rotz); Translation = XMMatrixTranslation( 0.0f, 0.0f, 4.0f ); //Set cube1's world space using the transformations cube1World = Translation * Rotation * Rotationx * Rotationz; ///////////////**************new**************//////////////////// //Reset cube2World cube2World = XMMatrixIdentity(); //Define cube2's world space matrix Rotation = XMMatrixRotationAxis( rotyaxis, -rot); ///////////////**************new**************//////////////////// Scale = XMMatrixScaling( scaleX, scaleY, 1.3f ); ///////////////**************new**************//////////////////// //Set cube2's world space matrix cube2World = Rotation * Scale; } ##Call the DetectInput() Function## Last but not least, we need to call the detect input function! 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 frameCount++; if(GetTime() > 1.0f) { fps = frameCount; frameCount = 0; StartTimer(); } frameTime = GetFrameTime(); ///////////////**************new**************//////////////////// DetectInput(frameTime); ///////////////**************new**************//////////////////// UpdateScene(frameTime); DrawScene(); } } return msg.wParam; } ##Exercise:## 1. Use the mouse wheel to zoom in and out of the scene. Here's the final code: main.cpp: //Include and link appropriate libraries and headers// #pragma comment(lib, "d3d11.lib") #pragma comment(lib, "d3dx11.lib") #pragma comment(lib, "d3dx10.lib") #pragma comment (lib, "D3D10_1.lib") #pragma comment (lib, "DXGI.lib") #pragma comment (lib, "D2D1.lib") #pragma comment (lib, "dwrite.lib") ///////////////**************new**************//////////////////// #pragma comment (lib, "dinput8.lib") #pragma comment (lib, "dxguid.lib") ///////////////**************new**************//////////////////// #include <windows.h> #include <d3d11.h> #include <d3dx11.h> #include <d3dx10.h> #include <xnamath.h> #include <D3D10_1.h> #include <DXGI.h> #include <D2D1.h> #include <sstream> #include <dwrite.h> ///////////////**************new**************//////////////////// #include <dinput.h> ///////////////**************new**************//////////////////// //Global Declarations - Interfaces// IDXGISwapChain* SwapChain; ID3D11Device* d3d11Device; ID3D11DeviceContext* d3d11DevCon; ID3D11RenderTargetView* renderTargetView; ID3D11Buffer* squareIndexBuffer; ID3D11DepthStencilView* depthStencilView; ID3D11Texture2D* depthStencilBuffer; ID3D11Buffer* squareVertBuffer; ID3D11VertexShader* VS; ID3D11PixelShader* PS; ID3D11PixelShader* D2D_PS; ID3D10Blob* VS_Buffer; ID3D10Blob* PS_Buffer; ID3D10Blob* D2D_PS_Buffer; ID3D11InputLayout* vertLayout; ID3D11Buffer* cbPerObjectBuffer; ID3D11BlendState* Transparency; ID3D11RasterizerState* CCWcullMode; ID3D11RasterizerState* CWcullMode; ID3D11ShaderResourceView* CubesTexture; ID3D11SamplerState* CubesTexSamplerState; ID3D11Buffer* cbPerFrameBuffer; ID3D10Device1 *d3d101Device; IDXGIKeyedMutex *keyedMutex11; IDXGIKeyedMutex *keyedMutex10; ID2D1RenderTarget *D2DRenderTarget; ID2D1SolidColorBrush *Brush; ID3D11Texture2D *BackBuffer11; ID3D11Texture2D *sharedTex11; ID3D11Buffer *d2dVertBuffer; ID3D11Buffer *d2dIndexBuffer; ID3D11ShaderResourceView *d2dTexture; IDWriteFactory *DWriteFactory; IDWriteTextFormat *TextFormat; ///////////////**************new**************//////////////////// IDirectInputDevice8* DIKeyboard; IDirectInputDevice8* DIMouse; ///////////////**************new**************//////////////////// std::wstring printText; //Global Declarations - Others// LPCTSTR WndClassName = L"firstwindow"; HWND hwnd = NULL; HRESULT hr; const int Width = 300; const int Height = 300; ///////////////**************new**************//////////////////// DIMOUSESTATE mouseLastState; LPDIRECTINPUT8 DirectInput; float rotx = 0; float rotz = 0; float scaleX = 1.0f; float scaleY = 1.0f; XMMATRIX Rotationx; XMMATRIX Rotationz; ///////////////**************new**************//////////////////// XMMATRIX WVP; XMMATRIX cube1World; XMMATRIX cube2World; XMMATRIX camView; XMMATRIX camProjection; XMMATRIX d2dWorld; XMVECTOR camPosition; XMVECTOR camTarget; XMVECTOR camUp; XMMATRIX Rotation; XMMATRIX Scale; XMMATRIX Translation; float rot = 0.01f; double countsPerSecond = 0.0; __int64 CounterStart = 0; int frameCount = 0; int fps = 0; __int64 frameTimeOld = 0; double frameTime; //Function Prototypes// bool InitializeDirect3d11App(HINSTANCE hInstance); void CleanUp(); bool InitScene(); void DrawScene(); bool InitD2D_D3D101_DWrite(IDXGIAdapter1 *Adapter); void InitD2DScreenTexture(); void UpdateScene(double time); void RenderText(std::wstring text, int inInt); void StartTimer(); double GetTime(); double GetFrameTime(); bool InitializeWindow(HINSTANCE hInstance, int ShowWnd, int width, int height, bool windowed); int messageloop(); ///////////////**************new**************//////////////////// bool InitDirectInput(HINSTANCE hInstance); void DetectInput(double time); ///////////////**************new**************//////////////////// LRESULT CALLBACK WndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam); //Create effects constant buffer's structure// struct cbPerObject { XMMATRIX WVP; XMMATRIX World; }; cbPerObject cbPerObj; struct Light { Light() { ZeroMemory(this, sizeof(Light)); } XMFLOAT3 dir; float pad; XMFLOAT4 ambient; XMFLOAT4 diffuse; }; Light light; struct cbPerFrame { Light light; }; cbPerFrame constbuffPerFrame; //Vertex Structure and Vertex Layout (Input Layout)// struct Vertex //Overloaded Vertex Structure { 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){} XMFLOAT3 pos; XMFLOAT2 texCoord; XMFLOAT3 normal; }; D3D11_INPUT_ELEMENT_DESC layout[] = { { "POSITION", 0, DXGI_FORMAT_R32G32B32_FLOAT, 0, 0, D3D11_INPUT_PER_VERTEX_DATA, 0 }, { "TEXCOORD", 0, DXGI_FORMAT_R32G32_FLOAT, 0, 12, D3D11_INPUT_PER_VERTEX_DATA, 0 }, { "NORMAL", 0, DXGI_FORMAT_R32G32B32_FLOAT, 0, 20, D3D11_INPUT_PER_VERTEX_DATA, 0} }; UINT numElements = ARRAYSIZE(layout); 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(!InitializeDirect3d11App(hInstance)) //Initialize Direct3D { MessageBox(0, L"Direct3D Initialization - Failed", L"Error", MB_OK); return 0; } if(!InitScene()) //Initialize our scene { MessageBox(0, L"Scene Initialization - Failed", L"Error", MB_OK); return 0; } ///////////////**************new**************//////////////////// if(!InitDirectInput(hInstance)) { MessageBox(0, L"Direct Input Initialization - Failed", L"Error", MB_OK); return 0; } ///////////////**************new**************//////////////////// messageloop(); CleanUp(); 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"Lesson 4 - Begin Drawing", 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 InitializeDirect3d11App(HINSTANCE hInstance) { //Describe our SwapChain Buffer DXGI_MODE_DESC bufferDesc; ZeroMemory(&bufferDesc, sizeof(DXGI_MODE_DESC)); bufferDesc.Width = Width; bufferDesc.Height = Height; bufferDesc.RefreshRate.Numerator = 60; bufferDesc.RefreshRate.Denominator = 1; bufferDesc.Format = DXGI_FORMAT_B8G8R8A8_UNORM; bufferDesc.ScanlineOrdering = DXGI_MODE_SCANLINE_ORDER_UNSPECIFIED; bufferDesc.Scaling = DXGI_MODE_SCALING_UNSPECIFIED; //Describe our SwapChain DXGI_SWAP_CHAIN_DESC swapChainDesc; ZeroMemory(&swapChainDesc, sizeof(DXGI_SWAP_CHAIN_DESC)); swapChainDesc.BufferDesc = bufferDesc; swapChainDesc.SampleDesc.Count = 1; swapChainDesc.SampleDesc.Quality = 0; swapChainDesc.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT; swapChainDesc.BufferCount = 1; swapChainDesc.OutputWindow = hwnd; swapChainDesc.Windowed = TRUE; swapChainDesc.SwapEffect = DXGI_SWAP_EFFECT_DISCARD; // Create DXGI factory to enumerate adapters/////////////////////////////////////////////////////////////////////////// IDXGIFactory1 *DXGIFactory; HRESULT hr = CreateDXGIFactory1(__uuidof(IDXGIFactory1), (void**)&DXGIFactory); // Use the first adapter IDXGIAdapter1 *Adapter; hr = DXGIFactory->EnumAdapters1(0, &Adapter); DXGIFactory->Release(); //Create our Direct3D 11 Device and SwapChain////////////////////////////////////////////////////////////////////////// hr = D3D11CreateDeviceAndSwapChain(Adapter, D3D_DRIVER_TYPE_UNKNOWN, NULL, D3D11_CREATE_DEVICE_BGRA_SUPPORT, NULL, NULL, D3D11_SDK_VERSION, &swapChainDesc, &SwapChain, &d3d11Device, NULL, &d3d11DevCon); //Initialize Direct2D, Direct3D 10.1, DirectWrite InitD2D_D3D101_DWrite(Adapter); //Release the Adapter interface Adapter->Release(); //Create our BackBuffer and Render Target hr = SwapChain->GetBuffer( 0, __uuidof( ID3D11Texture2D ), (void**)&BackBuffer11 ); hr = d3d11Device->CreateRenderTargetView( BackBuffer11, NULL, &renderTargetView ); //Describe our Depth/Stencil Buffer D3D11_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 = D3D11_USAGE_DEFAULT; depthStencilDesc.BindFlags = D3D11_BIND_DEPTH_STENCIL; depthStencilDesc.CPUAccessFlags = 0; depthStencilDesc.MiscFlags = 0; //Create the Depth/Stencil View d3d11Device->CreateTexture2D(&depthStencilDesc, NULL, &depthStencilBuffer); d3d11Device->CreateDepthStencilView(depthStencilBuffer, NULL, &depthStencilView); return true; } bool InitD2D_D3D101_DWrite(IDXGIAdapter1 *Adapter) { //Create our Direc3D 10.1 Device/////////////////////////////////////////////////////////////////////////////////////// hr = D3D10CreateDevice1(Adapter, D3D10_DRIVER_TYPE_HARDWARE, NULL,D3D10_CREATE_DEVICE_BGRA_SUPPORT, D3D10_FEATURE_LEVEL_9_3, D3D10_1_SDK_VERSION, &d3d101Device ); //Create Shared Texture that Direct3D 10.1 will render on////////////////////////////////////////////////////////////// D3D11_TEXTURE2D_DESC sharedTexDesc; ZeroMemory(&sharedTexDesc, sizeof(sharedTexDesc)); sharedTexDesc.Width = Width; sharedTexDesc.Height = Height; sharedTexDesc.Format = DXGI_FORMAT_B8G8R8A8_UNORM; sharedTexDesc.MipLevels = 1; sharedTexDesc.ArraySize = 1; sharedTexDesc.SampleDesc.Count = 1; sharedTexDesc.Usage = D3D11_USAGE_DEFAULT; sharedTexDesc.BindFlags = D3D11_BIND_SHADER_RESOURCE | D3D11_BIND_RENDER_TARGET; sharedTexDesc.MiscFlags = D3D11_RESOURCE_MISC_SHARED_KEYEDMUTEX; hr = d3d11Device->CreateTexture2D(&sharedTexDesc, NULL, &sharedTex11); // Get the keyed mutex for the shared texture (for D3D11)/////////////////////////////////////////////////////////////// hr = sharedTex11->QueryInterface(__uuidof(IDXGIKeyedMutex), (void**)&keyedMutex11); // Get the shared handle needed to open the shared texture in D3D10.1/////////////////////////////////////////////////// IDXGIResource *sharedResource10; HANDLE sharedHandle10; hr = sharedTex11->QueryInterface(__uuidof(IDXGIResource), (void**)&sharedResource10); hr = sharedResource10->GetSharedHandle(&sharedHandle10); sharedResource10->Release(); // Open the surface for the shared texture in D3D10.1/////////////////////////////////////////////////////////////////// IDXGISurface1 *sharedSurface10; hr = d3d101Device->OpenSharedResource(sharedHandle10, __uuidof(IDXGISurface1), (void**)(&sharedSurface10)); hr = sharedSurface10->QueryInterface(__uuidof(IDXGIKeyedMutex), (void**)&keyedMutex10); // Create D2D factory/////////////////////////////////////////////////////////////////////////////////////////////////// ID2D1Factory *D2DFactory; hr = D2D1CreateFactory(D2D1_FACTORY_TYPE_SINGLE_THREADED, __uuidof(ID2D1Factory), (void**)&D2DFactory); D2D1_RENDER_TARGET_PROPERTIES renderTargetProperties; ZeroMemory(&renderTargetProperties, sizeof(renderTargetProperties)); renderTargetProperties.type = D2D1_RENDER_TARGET_TYPE_HARDWARE; renderTargetProperties.pixelFormat = D2D1::PixelFormat(DXGI_FORMAT_UNKNOWN, D2D1_ALPHA_MODE_PREMULTIPLIED); hr = D2DFactory->CreateDxgiSurfaceRenderTarget(sharedSurface10, &renderTargetProperties, &D2DRenderTarget); sharedSurface10->Release(); D2DFactory->Release(); // Create a solid color brush to draw something with hr = D2DRenderTarget->CreateSolidColorBrush(D2D1::ColorF(1.0f, 1.0f, 1.0f, 1.0f), &Brush); //DirectWrite/////////////////////////////////////////////////////////////////////////////////////////////////////////// hr = DWriteCreateFactory(DWRITE_FACTORY_TYPE_SHARED, __uuidof(IDWriteFactory), reinterpret_cast<IUnknown**>(&DWriteFactory)); hr = DWriteFactory->CreateTextFormat( L"Script", NULL, DWRITE_FONT_WEIGHT_REGULAR, DWRITE_FONT_STYLE_NORMAL, DWRITE_FONT_STRETCH_NORMAL, 24.0f, L"en-us", &TextFormat ); hr = TextFormat->SetTextAlignment(DWRITE_TEXT_ALIGNMENT_LEADING); hr = TextFormat->SetParagraphAlignment(DWRITE_PARAGRAPH_ALIGNMENT_NEAR); d3d101Device->IASetPrimitiveTopology(D3D10_PRIMITIVE_TOPOLOGY_POINTLIST); return true; } ///////////////**************new**************//////////////////// bool InitDirectInput(HINSTANCE hInstance) { hr = DirectInput8Create(hInstance, DIRECTINPUT_VERSION, IID_IDirectInput8, (void**)&DirectInput, NULL); hr = DirectInput->CreateDevice(GUID_SysKeyboard, &DIKeyboard, NULL); hr = DirectInput->CreateDevice(GUID_SysMouse, &DIMouse, NULL); hr = DIKeyboard->SetDataFormat(&c_dfDIKeyboard); hr = DIKeyboard->SetCooperativeLevel(hwnd, DISCL_FOREGROUND | DISCL_NONEXCLUSIVE); hr = DIMouse->SetDataFormat(&c_dfDIMouse); hr = DIMouse->SetCooperativeLevel(hwnd, DISCL_EXCLUSIVE | DISCL_NOWINKEY | DISCL_FOREGROUND); return true; } void DetectInput(double time) { 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 -= 1.0f * time; } if(keyboardState[DIK_RIGHT] & 0x80) { rotz += 1.0f * time; } if(keyboardState[DIK_UP] & 0x80) { rotx += 1.0f * time; } if(keyboardState[DIK_DOWN] & 0x80) { rotx -= 1.0f * time; } if(mouseCurrState.lX != mouseLastState.lX) { scaleX -= (mouseCurrState.lX * 0.001f); } if(mouseCurrState.lY != mouseLastState.lY) { scaleY -= (mouseCurrState.lY * 0.001f); } if ( rotx > 6.28 ) rotx -= 6.28; else if ( rotx < 0 ) rotx = 6.28 + rotx; if ( rotz > 6.28 ) rotz -= 6.28; else if ( rotz < 0 ) rotz = 6.28 + rotz; mouseLastState = mouseCurrState; return; } ///////////////**************new**************//////////////////// void CleanUp() { //Release the COM Objects we created SwapChain->Release(); d3d11Device->Release(); d3d11DevCon->Release(); renderTargetView->Release(); squareVertBuffer->Release(); squareIndexBuffer->Release(); VS->Release(); PS->Release(); VS_Buffer->Release(); PS_Buffer->Release(); vertLayout->Release(); depthStencilView->Release(); depthStencilBuffer->Release(); cbPerObjectBuffer->Release(); Transparency->Release(); CCWcullMode->Release(); CWcullMode->Release(); d3d101Device->Release(); keyedMutex11->Release(); keyedMutex10->Release(); D2DRenderTarget->Release(); Brush->Release(); BackBuffer11->Release(); sharedTex11->Release(); DWriteFactory->Release(); TextFormat->Release(); d2dTexture->Release(); cbPerFrameBuffer->Release(); ///////////////**************new**************//////////////////// DIKeyboard->Unacquire(); DIMouse->Unacquire(); DirectInput->Release(); ///////////////**************new**************//////////////////// } void InitD2DScreenTexture() { //Create the vertex buffer Vertex v[] = { // Front Face Vertex(-1.0f, -1.0f, -1.0f, 0.0f, 1.0f,-1.0f, -1.0f, -1.0f), Vertex(-1.0f, 1.0f, -1.0f, 0.0f, 0.0f,-1.0f, 1.0f, -1.0f), Vertex( 1.0f, 1.0f, -1.0f, 1.0f, 0.0f, 1.0f, 1.0f, -1.0f), Vertex( 1.0f, -1.0f, -1.0f, 1.0f, 1.0f, 1.0f, -1.0f, -1.0f), }; DWORD indices[] = { // Front Face 0, 1, 2, 0, 2, 3, }; D3D11_BUFFER_DESC indexBufferDesc; ZeroMemory( &indexBufferDesc, sizeof(indexBufferDesc) ); indexBufferDesc.Usage = D3D11_USAGE_DEFAULT; indexBufferDesc.ByteWidth = sizeof(DWORD) * 2 * 3; indexBufferDesc.BindFlags = D3D11_BIND_INDEX_BUFFER; indexBufferDesc.CPUAccessFlags = 0; indexBufferDesc.MiscFlags = 0; D3D11_SUBRESOURCE_DATA iinitData; iinitData.pSysMem = indices; d3d11Device->CreateBuffer(&indexBufferDesc, &iinitData, &d2dIndexBuffer); D3D11_BUFFER_DESC vertexBufferDesc; ZeroMemory( &vertexBufferDesc, sizeof(vertexBufferDesc) ); vertexBufferDesc.Usage = D3D11_USAGE_DEFAULT; vertexBufferDesc.ByteWidth = sizeof( Vertex ) * 4; vertexBufferDesc.BindFlags = D3D11_BIND_VERTEX_BUFFER; vertexBufferDesc.CPUAccessFlags = 0; vertexBufferDesc.MiscFlags = 0; D3D11_SUBRESOURCE_DATA vertexBufferData; ZeroMemory( &vertexBufferData, sizeof(vertexBufferData) ); vertexBufferData.pSysMem = v; hr = d3d11Device->CreateBuffer( &vertexBufferDesc, &vertexBufferData, &d2dVertBuffer); //Create A shader resource view from the texture D2D will render to, //So we can use it to texture a square which overlays our scene d3d11Device->CreateShaderResourceView(sharedTex11, NULL, &d2dTexture); } bool InitScene() { InitD2DScreenTexture(); //Compile Shaders from shader file hr = D3DX11CompileFromFile(L"Effects.fx", 0, 0, "VS", "vs_4_0", 0, 0, 0, &VS_Buffer, 0, 0); hr = D3DX11CompileFromFile(L"Effects.fx", 0, 0, "PS", "ps_4_0", 0, 0, 0, &PS_Buffer, 0, 0); hr = D3DX11CompileFromFile(L"Effects.fx", 0, 0, "D2D_PS", "ps_4_0", 0, 0, 0, &D2D_PS_Buffer, 0, 0); //Create the Shader Objects hr = d3d11Device->CreateVertexShader(VS_Buffer->GetBufferPointer(), VS_Buffer->GetBufferSize(), NULL, &VS); hr = d3d11Device->CreatePixelShader(PS_Buffer->GetBufferPointer(), PS_Buffer->GetBufferSize(), NULL, &PS); hr = d3d11Device->CreatePixelShader(D2D_PS_Buffer->GetBufferPointer(), D2D_PS_Buffer->GetBufferSize(), NULL, &D2D_PS); //Set Vertex and Pixel Shaders d3d11DevCon->VSSetShader(VS, 0, 0); d3d11DevCon->PSSetShader(PS, 0, 0); light.dir = XMFLOAT3(0.25f, 0.5f, -1.0f); light.ambient = XMFLOAT4(0.2f, 0.2f, 0.2f, 1.0f); light.diffuse = XMFLOAT4(1.0f, 1.0f, 1.0f, 1.0f); //Create the vertex buffer Vertex v[] = { // Front Face Vertex(-1.0f, -1.0f, -1.0f, 0.0f, 1.0f,-1.0f, -1.0f, -1.0f), Vertex(-1.0f, 1.0f, -1.0f, 0.0f, 0.0f,-1.0f, 1.0f, -1.0f), Vertex( 1.0f, 1.0f, -1.0f, 1.0f, 0.0f, 1.0f, 1.0f, -1.0f), Vertex( 1.0f, -1.0f, -1.0f, 1.0f, 1.0f, 1.0f, -1.0f, -1.0f), // Back Face Vertex(-1.0f, -1.0f, 1.0f, 1.0f, 1.0f,-1.0f, -1.0f, 1.0f), Vertex( 1.0f, -1.0f, 1.0f, 0.0f, 1.0f, 1.0f, -1.0f, 1.0f), Vertex( 1.0f, 1.0f, 1.0f, 0.0f, 0.0f, 1.0f, 1.0f, 1.0f), Vertex(-1.0f, 1.0f, 1.0f, 1.0f, 0.0f,-1.0f, 1.0f, 1.0f), // Top Face Vertex(-1.0f, 1.0f, -1.0f, 0.0f, 1.0f,-1.0f, 1.0f, -1.0f), Vertex(-1.0f, 1.0f, 1.0f, 0.0f, 0.0f,-1.0f, 1.0f, 1.0f), Vertex( 1.0f, 1.0f, 1.0f, 1.0f, 0.0f, 1.0f, 1.0f, 1.0f), Vertex( 1.0f, 1.0f, -1.0f, 1.0f, 1.0f, 1.0f, 1.0f, -1.0f), // Bottom Face Vertex(-1.0f, -1.0f, -1.0f, 1.0f, 1.0f,-1.0f, -1.0f, -1.0f), Vertex( 1.0f, -1.0f, -1.0f, 0.0f, 1.0f, 1.0f, -1.0f, -1.0f), Vertex( 1.0f, -1.0f, 1.0f, 0.0f, 0.0f, 1.0f, -1.0f, 1.0f), Vertex(-1.0f, -1.0f, 1.0f, 1.0f, 0.0f,-1.0f, -1.0f, 1.0f), // Left Face Vertex(-1.0f, -1.0f, 1.0f, 0.0f, 1.0f,-1.0f, -1.0f, 1.0f), Vertex(-1.0f, 1.0f, 1.0f, 0.0f, 0.0f,-1.0f, 1.0f, 1.0f), Vertex(-1.0f, 1.0f, -1.0f, 1.0f, 0.0f,-1.0f, 1.0f, -1.0f), Vertex(-1.0f, -1.0f, -1.0f, 1.0f, 1.0f,-1.0f, -1.0f, -1.0f), // Right Face Vertex( 1.0f, -1.0f, -1.0f, 0.0f, 1.0f, 1.0f, -1.0f, -1.0f), Vertex( 1.0f, 1.0f, -1.0f, 0.0f, 0.0f, 1.0f, 1.0f, -1.0f), Vertex( 1.0f, 1.0f, 1.0f, 1.0f, 0.0f, 1.0f, 1.0f, 1.0f), Vertex( 1.0f, -1.0f, 1.0f, 1.0f, 1.0f, 1.0f, -1.0f, 1.0f), }; DWORD indices[] = { // Front Face 0, 1, 2, 0, 2, 3, // Back Face 4, 5, 6, 4, 6, 7, // Top Face 8, 9, 10, 8, 10, 11, // Bottom Face 12, 13, 14, 12, 14, 15, // Left Face 16, 17, 18, 16, 18, 19, // Right Face 20, 21, 22, 20, 22, 23 }; D3D11_BUFFER_DESC indexBufferDesc; ZeroMemory( &indexBufferDesc, sizeof(indexBufferDesc) ); indexBufferDesc.Usage = D3D11_USAGE_DEFAULT; indexBufferDesc.ByteWidth = sizeof(DWORD) * 12 * 3; indexBufferDesc.BindFlags = D3D11_BIND_INDEX_BUFFER; indexBufferDesc.CPUAccessFlags = 0; indexBufferDesc.MiscFlags = 0; D3D11_SUBRESOURCE_DATA iinitData; iinitData.pSysMem = indices; d3d11Device->CreateBuffer(&indexBufferDesc, &iinitData, &squareIndexBuffer); D3D11_BUFFER_DESC vertexBufferDesc; ZeroMemory( &vertexBufferDesc, sizeof(vertexBufferDesc) ); vertexBufferDesc.Usage = D3D11_USAGE_DEFAULT; vertexBufferDesc.ByteWidth = sizeof( Vertex ) * 24; vertexBufferDesc.BindFlags = D3D11_BIND_VERTEX_BUFFER; vertexBufferDesc.CPUAccessFlags = 0; vertexBufferDesc.MiscFlags = 0; D3D11_SUBRESOURCE_DATA vertexBufferData; ZeroMemory( &vertexBufferData, sizeof(vertexBufferData) ); vertexBufferData.pSysMem = v; hr = d3d11Device->CreateBuffer( &vertexBufferDesc, &vertexBufferData, &squareVertBuffer); //Create the Input Layout hr = d3d11Device->CreateInputLayout( layout, numElements, VS_Buffer->GetBufferPointer(), VS_Buffer->GetBufferSize(), &vertLayout ); //Set the Input Layout d3d11DevCon->IASetInputLayout( vertLayout ); //Set Primitive Topology d3d11DevCon->IASetPrimitiveTopology( D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST ); //Create the Viewport D3D11_VIEWPORT viewport; ZeroMemory(&viewport, sizeof(D3D11_VIEWPORT)); viewport.TopLeftX = 0; viewport.TopLeftY = 0; viewport.Width = Width; viewport.Height = Height; viewport.MinDepth = 0.0f; viewport.MaxDepth = 1.0f; //Set the Viewport d3d11DevCon->RSSetViewports(1, &viewport); //Create the buffer to send to the cbuffer in effect file D3D11_BUFFER_DESC cbbd; ZeroMemory(&cbbd, sizeof(D3D11_BUFFER_DESC)); cbbd.Usage = D3D11_USAGE_DEFAULT; cbbd.ByteWidth = sizeof(cbPerObject); cbbd.BindFlags = D3D11_BIND_CONSTANT_BUFFER; cbbd.CPUAccessFlags = 0; cbbd.MiscFlags = 0; hr = d3d11Device->CreateBuffer(&cbbd, NULL, &cbPerObjectBuffer); //Create the buffer to send to the cbuffer per frame in effect file ZeroMemory(&cbbd, sizeof(D3D11_BUFFER_DESC)); cbbd.Usage = D3D11_USAGE_DEFAULT; cbbd.ByteWidth = sizeof(cbPerFrame); cbbd.BindFlags = D3D11_BIND_CONSTANT_BUFFER; cbbd.CPUAccessFlags = 0; cbbd.MiscFlags = 0; hr = d3d11Device->CreateBuffer(&cbbd, NULL, &cbPerFrameBuffer); //Camera information camPosition = XMVectorSet( 0.0f, 3.0f, -8.0f, 0.0f ); camTarget = XMVectorSet( 0.0f, 0.0f, 0.0f, 0.0f ); camUp = XMVectorSet( 0.0f, 1.0f, 0.0f, 0.0f ); //Set the View matrix camView = XMMatrixLookAtLH( camPosition, camTarget, camUp ); //Set the Projection matrix camProjection = XMMatrixPerspectiveFovLH( 0.4f*3.14f, (float)Width/Height, 1.0f, 1000.0f); D3D11_BLEND_DESC blendDesc; ZeroMemory( &blendDesc, sizeof(blendDesc) ); D3D11_RENDER_TARGET_BLEND_DESC rtbd; ZeroMemory( &rtbd, sizeof(rtbd) ); rtbd.BlendEnable = true; rtbd.SrcBlend = D3D11_BLEND_SRC_COLOR; rtbd.DestBlend = D3D11_BLEND_INV_SRC_ALPHA; rtbd.BlendOp = D3D11_BLEND_OP_ADD; rtbd.SrcBlendAlpha = D3D11_BLEND_ONE; rtbd.DestBlendAlpha = D3D11_BLEND_ZERO; rtbd.BlendOpAlpha = D3D11_BLEND_OP_ADD; rtbd.RenderTargetWriteMask = D3D10_COLOR_WRITE_ENABLE_ALL; blendDesc.AlphaToCoverageEnable = false; blendDesc.RenderTarget[0] = rtbd; hr = D3DX11CreateShaderResourceViewFromFile( d3d11Device, L"braynzar.jpg", NULL, NULL, &CubesTexture, NULL ); // Describe the Sample State D3D11_SAMPLER_DESC sampDesc; ZeroMemory( &sampDesc, sizeof(sampDesc) ); sampDesc.Filter = D3D11_FILTER_MIN_MAG_MIP_LINEAR; sampDesc.AddressU = D3D11_TEXTURE_ADDRESS_WRAP; sampDesc.AddressV = D3D11_TEXTURE_ADDRESS_WRAP; sampDesc.AddressW = D3D11_TEXTURE_ADDRESS_WRAP; sampDesc.ComparisonFunc = D3D11_COMPARISON_NEVER; sampDesc.MinLOD = 0; sampDesc.MaxLOD = D3D11_FLOAT32_MAX; //Create the Sample State hr = d3d11Device->CreateSamplerState( &sampDesc, &CubesTexSamplerState ); d3d11Device->CreateBlendState(&blendDesc, &Transparency); D3D11_RASTERIZER_DESC cmdesc; ZeroMemory(&cmdesc, sizeof(D3D11_RASTERIZER_DESC)); cmdesc.FillMode = D3D11_FILL_SOLID; cmdesc.CullMode = D3D11_CULL_BACK; cmdesc.FrontCounterClockwise = true; hr = d3d11Device->CreateRasterizerState(&cmdesc, &CCWcullMode); cmdesc.FrontCounterClockwise = false; hr = d3d11Device->CreateRasterizerState(&cmdesc, &CWcullMode); return true; } void StartTimer() { LARGE_INTEGER frequencyCount; QueryPerformanceFrequency(&frequencyCount); countsPerSecond = double(frequencyCount.QuadPart); QueryPerformanceCounter(&frequencyCount); CounterStart = frequencyCount.QuadPart; } double GetTime() { LARGE_INTEGER currentTime; QueryPerformanceCounter(&currentTime); return double(currentTime.QuadPart-CounterStart)/countsPerSecond; } double GetFrameTime() { LARGE_INTEGER currentTime; __int64 tickCount; QueryPerformanceCounter(&currentTime); tickCount = currentTime.QuadPart-frameTimeOld; frameTimeOld = currentTime.QuadPart; if(tickCount < 0.0f) tickCount = 0.0f; return float(tickCount)/countsPerSecond; } void UpdateScene(double time) { //Keep the cubes rotating rot += 1.0f * time; if(rot > 6.28f) rot = 0.0f; //Reset cube1World cube1World = XMMatrixIdentity(); //Define cube1's world space matrix ///////////////**************new**************//////////////////// XMVECTOR rotyaxis = XMVectorSet(0.0f, 1.0f, 0.0f, 0.0f); XMVECTOR rotzaxis = XMVectorSet(0.0f, 0.0f, 1.0f, 0.0f); XMVECTOR rotxaxis = XMVectorSet(1.0f, 0.0f, 0.0f, 0.0f); Rotation = XMMatrixRotationAxis(rotyaxis, rot); Rotationx = XMMatrixRotationAxis(rotxaxis, rotx); Rotationz = XMMatrixRotationAxis(rotzaxis, rotz); Translation = XMMatrixTranslation( 0.0f, 0.0f, 4.0f ); //Set cube1's world space using the transformations cube1World = Translation * Rotation * Rotationx * Rotationz; ///////////////**************new**************//////////////////// //Reset cube2World cube2World = XMMatrixIdentity(); //Define cube2's world space matrix Rotation = XMMatrixRotationAxis( rotyaxis, -rot); ///////////////**************new**************//////////////////// Scale = XMMatrixScaling( scaleX, scaleY, 1.3f ); ///////////////**************new**************//////////////////// //Set cube2's world space matrix cube2World = Rotation * Scale; } void RenderText(std::wstring text, int inInt) { d3d11DevCon->PSSetShader(D2D_PS, 0, 0); //Release the D3D 11 Device keyedMutex11->ReleaseSync(0); //Use D3D10.1 device keyedMutex10->AcquireSync(0, 5); //Draw D2D content D2DRenderTarget->BeginDraw(); //Clear D2D Background D2DRenderTarget->Clear(D2D1::ColorF(0.0f, 0.0f, 0.0f, 0.0f)); //Create our string std::wostringstream printString; printString << text << inInt; printText = printString.str(); //Set the Font Color D2D1_COLOR_F FontColor = D2D1::ColorF(1.0f, 1.0f, 1.0f, 1.0f); //Set the brush color D2D will use to draw with Brush->SetColor(FontColor); //Create the D2D Render Area D2D1_RECT_F layoutRect = D2D1::RectF(0, 0, Width, Height); //Draw the Text D2DRenderTarget->DrawText( printText.c_str(), wcslen(printText.c_str()), TextFormat, layoutRect, Brush ); D2DRenderTarget->EndDraw(); //Release the D3D10.1 Device keyedMutex10->ReleaseSync(1); //Use the D3D11 Device keyedMutex11->AcquireSync(1, 5); //Use the shader resource representing the direct2d render target //to texture a square which is rendered in screen space so it //overlays on top of our entire scene. We use alpha blending so //that the entire background of the D2D render target is "invisible", //And only the stuff we draw with D2D will be visible (the text) //Set the blend state for D2D render target texture objects d3d11DevCon->OMSetBlendState(Transparency, NULL, 0xffffffff); //Set the d2d Index buffer d3d11DevCon->IASetIndexBuffer( d2dIndexBuffer, DXGI_FORMAT_R32_UINT, 0); //Set the d2d vertex buffer UINT stride = sizeof( Vertex ); UINT offset = 0; d3d11DevCon->IASetVertexBuffers( 0, 1, &d2dVertBuffer, &stride, &offset ); WVP = XMMatrixIdentity(); cbPerObj.World = XMMatrixTranspose(WVP); cbPerObj.WVP = XMMatrixTranspose(WVP); d3d11DevCon->UpdateSubresource( cbPerObjectBuffer, 0, NULL, &cbPerObj, 0, 0 ); d3d11DevCon->VSSetConstantBuffers( 0, 1, &cbPerObjectBuffer ); d3d11DevCon->PSSetShaderResources( 0, 1, &d2dTexture ); d3d11DevCon->PSSetSamplers( 0, 1, &CubesTexSamplerState ); d3d11DevCon->RSSetState(CWcullMode); //Draw the second cube d3d11DevCon->DrawIndexed( 6, 0, 0 ); } void DrawScene() { //Clear our render target and depth/stencil view float bgColor[4] = {(0.0f, 0.0f, 0.0f, 0.0f)}; d3d11DevCon->ClearRenderTargetView(renderTargetView, bgColor); d3d11DevCon->ClearDepthStencilView(depthStencilView, D3D11_CLEAR_DEPTH|D3D11_CLEAR_STENCIL, 1.0f, 0); constbuffPerFrame.light = light; d3d11DevCon->UpdateSubresource( cbPerFrameBuffer, 0, NULL, &constbuffPerFrame, 0, 0 ); d3d11DevCon->PSSetConstantBuffers(0, 1, &cbPerFrameBuffer); //Set our Render Target d3d11DevCon->OMSetRenderTargets( 1, &renderTargetView, depthStencilView ); //Set the default blend state (no blending) for opaque objects d3d11DevCon->OMSetBlendState(0, 0, 0xffffffff); d3d11DevCon->VSSetShader(VS, 0, 0); d3d11DevCon->PSSetShader(PS, 0, 0); //Set the cubes index buffer d3d11DevCon->IASetIndexBuffer( squareIndexBuffer, DXGI_FORMAT_R32_UINT, 0); //Set the cubes vertex buffer UINT stride = sizeof( Vertex ); UINT offset = 0; d3d11DevCon->IASetVertexBuffers( 0, 1, &squareVertBuffer, &stride, &offset ); //Set the WVP matrix and send it to the constant buffer in effect file WVP = cube1World * camView * camProjection; cbPerObj.World = XMMatrixTranspose(cube1World); cbPerObj.WVP = XMMatrixTranspose(WVP); d3d11DevCon->UpdateSubresource( cbPerObjectBuffer, 0, NULL, &cbPerObj, 0, 0 ); d3d11DevCon->VSSetConstantBuffers( 0, 1, &cbPerObjectBuffer ); d3d11DevCon->PSSetShaderResources( 0, 1, &CubesTexture ); d3d11DevCon->PSSetSamplers( 0, 1, &CubesTexSamplerState ); d3d11DevCon->RSSetState(CWcullMode); d3d11DevCon->DrawIndexed( 36, 0, 0 ); WVP = cube2World * camView * camProjection; cbPerObj.World = XMMatrixTranspose(cube2World); cbPerObj.WVP = XMMatrixTranspose(WVP); d3d11DevCon->UpdateSubresource( cbPerObjectBuffer, 0, NULL, &cbPerObj, 0, 0 ); d3d11DevCon->VSSetConstantBuffers( 0, 1, &cbPerObjectBuffer ); d3d11DevCon->PSSetShaderResources( 0, 1, &CubesTexture ); d3d11DevCon->PSSetSamplers( 0, 1, &CubesTexSamplerState ); d3d11DevCon->RSSetState(CWcullMode); d3d11DevCon->DrawIndexed( 36, 0, 0 ); RenderText(L"FPS: ", fps); //Present the backbuffer to the screen SwapChain->Present(0, 0); } 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 frameCount++; if(GetTime() > 1.0f) { fps = frameCount; frameCount = 0; StartTimer(); } frameTime = GetFrameTime(); ///////////////**************new**************//////////////////// DetectInput(frameTime); ///////////////**************new**************//////////////////// UpdateScene(frameTime); DrawScene(); } } return msg.wParam; } LRESULT CALLBACK WndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) { switch( msg ) { case WM_KEYDOWN: if( wParam == VK_ESCAPE ){ DestroyWindow(hwnd); } return 0; case WM_DESTROY: PostQuitMessage(0); return 0; } return DefWindowProc(hwnd, msg, wParam, lParam); } Effects.fx: struct Light { float3 dir; float4 ambient; float4 diffuse; }; cbuffer cbPerFrame { Light light; }; cbuffer cbPerObject { float4x4 WVP; float4x4 World; }; Texture2D ObjTexture; SamplerState ObjSamplerState; struct VS_OUTPUT { float4 Pos : SV_POSITION; float2 TexCoord : TEXCOORD; float3 normal : NORMAL; }; VS_OUTPUT VS(float4 inPos : POSITION, float2 inTexCoord : TEXCOORD, float3 normal : NORMAL) { VS_OUTPUT output; output.Pos = mul(inPos, WVP); output.normal = mul(normal, World); output.TexCoord = inTexCoord; return output; } float4 PS(VS_OUTPUT input) : SV_TARGET { input.normal = normalize(input.normal); float4 diffuse = ObjTexture.Sample( ObjSamplerState, input.TexCoord ); float3 finalColor; finalColor = diffuse * light.ambient; finalColor += saturate(dot(light.dir, input.normal) * light.diffuse * diffuse); return float4(finalColor, diffuse.a); } float4 D2D_PS(VS_OUTPUT input) : SV_TARGET { float4 diffuse = ObjTexture.Sample( ObjSamplerState, input.TexCoord ); return diffuse; }