Skip to content

Instantly share code, notes, and snippets.

@krupitskas
Created November 1, 2014 19:41
Show Gist options
  • Select an option

  • Save krupitskas/bc24880d29a0043321a1 to your computer and use it in GitHub Desktop.

Select an option

Save krupitskas/bc24880d29a0043321a1 to your computer and use it in GitHub Desktop.

Revisions

  1. Nikita created this gist Nov 1, 2014.
    832 changes: 832 additions & 0 deletions directx
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,832 @@
    #pragma comment (lib, "dinput8.lib")
    #pragma comment (lib, "dxguid.lib")
    #include <dinput.h>
    #include <windows.h>
    #include <d3d11.h>
    #include <d3dx11.h>
    #include <d3dcompiler.h>
    #include <xnamath.h>
    #include "resource.h"
    #include <D3dx9shape.h>

    #define MX_SETWORLD 0x101
    #define MX_SETWORLD2 0x102

    //--------------------------------------------------------------------------------------
    // Для инпута
    //--------------------------------------------------------------------------------------
    IDirectInputDevice8* DIKeyboard;
    LPDIRECTINPUT8 DirectInput;

    bool InitDirectInput(HINSTANCE hInstance);
    void DetectInput(double time);

    float movY1 = 0;
    float movX1 = 0;

    float movY2 = 0;
    float movX2 = 0;


    //--------------------------------------------------------------------------------------
    // Структуры
    //--------------------------------------------------------------------------------------

    // Структура вершины
    struct SimpleVertex
    {
    XMFLOAT3 Pos; // Координаты точки в пространстве
    XMFLOAT3 Normal; // Нормаль вершины
    };


    // Структура константного буфера (совпадает со структурой в шейдере)
    struct ConstantBuffer
    {
    XMMATRIX mWorld; // Матрица мира
    XMMATRIX mView; // Матрица вида
    XMMATRIX mProjection; // Матрица проекции
    XMFLOAT4 vLightDir[3]; // Направление света
    XMFLOAT4 vLightColor[3];// Цвет источника
    XMFLOAT4 vOutputColor; // Активный цвет (для второго PSSolid)
    XMFLOAT3 Eye; //Откуда смотрим для зеркалки

    };


    //--------------------------------------------------------------------------------------
    // Глобальные переменные
    //--------------------------------------------------------------------------------------
    HINSTANCE g_hInst = NULL;
    HWND g_hWnd = NULL;
    D3D_DRIVER_TYPE g_driverType = D3D_DRIVER_TYPE_NULL;
    D3D_FEATURE_LEVEL g_featureLevel = D3D_FEATURE_LEVEL_11_0;
    ID3D11Device* g_pd3dDevice = NULL; // Устройство (для создания объектов)
    ID3D11DeviceContext* g_pImmediateContext = NULL; // Контекст (устройство рисования)
    IDXGISwapChain* g_pSwapChain = NULL; // Цепь связи (буфера с экраном)
    ID3D11RenderTargetView* g_pRenderTargetView = NULL; // Объект вида, задний буфер
    ID3D11Texture2D* g_pDepthStencil = NULL; // Текстура буфера глубин
    ID3D11DepthStencilView* g_pDepthStencilView = NULL; // Объект вида, буфер глубин

    ID3D11VertexShader* g_pVertexShader = NULL; // Вершинный шейдер
    ID3D11PixelShader* g_pPixelShader = NULL; // Пиксельный шейдер для куба
    ID3D11PixelShader* g_pPixelShader2 = NULL; // Пиксельный шейдер для куба 2
    ID3D11PixelShader* g_pPixelShaderSolid = NULL; // Пиксельный шейдер для источников света
    ID3D11InputLayout* g_pVertexLayout = NULL; // Описание формата вершин
    ID3D11Buffer* g_pVertexBuffer = NULL; // Буфер вершин
    ID3D11Buffer* g_pIndexBuffer = NULL; // Буфер индексов вершин
    ID3D11Buffer* g_pConstantBuffer = NULL; // Константный буфер

    XMMATRIX g_World; // Матрица мира
    XMMATRIX g_View; // Матрица вида
    XMMATRIX g_Projection; // Матрица проекции
    FLOAT t = 0.0f;


    XMFLOAT4 Eye = { 0.0f, 4.0f, -20.0f, 0.0f };

    XMFLOAT4 vLightDirs[3]; // Направление света (позиция источников)
    XMFLOAT4 vLightColors[3]; // Цвет источников


    //--------------------------------------------------------------------------------------
    // Предварительные объявления функций
    //--------------------------------------------------------------------------------------
    HRESULT InitWindow( HINSTANCE hInstance, int nCmdShow ); // Создание окна
    HRESULT InitDevice(); // Инициализация устройств DirectX
    HRESULT InitGeometry(); // Инициализация шаблона ввода и буфера вершин
    HRESULT InitMatrixes(); // Инициализация матриц
    void UpdateLight(); // Обновление параметров света
    void UpdateMatrix(UINT nLightIndex); // Обновление матрицы мира
    void Render(); // Функция рисования
    void CleanupDevice(); // Удаление созданнных устройств DirectX
    LRESULT CALLBACK WndProc( HWND, UINT, WPARAM, LPARAM ); // Функция окна


    //--------------------------------------------------------------------------------------
    // Точка входа в программу. Инициализация всех объектов и вход в цикл сообщений.
    // Свободное время используется для отрисовки сцены.
    //--------------------------------------------------------------------------------------
    int WINAPI wWinMain( HINSTANCE hInstance, HINSTANCE hPrevInstance, LPWSTR lpCmdLine, int nCmdShow )
    {
    UNREFERENCED_PARAMETER( hPrevInstance );
    UNREFERENCED_PARAMETER( lpCmdLine );

    // Создание окна приложения
    if( FAILED( InitWindow( hInstance, nCmdShow ) ) )
    return 0;

    // Создание объектов DirectX
    if( FAILED( InitDevice() ) )
    {
    MessageBox(0, L"Direct object creation failed",
    L"Error", MB_OK);
    CleanupDevice();
    return 0;
    }

    // Создание шейдеров и буфера вершин
    if( FAILED( InitGeometry() ) )
    {
    MessageBox(0, L"Direct geometry creation failed",
    L"Error", MB_OK);
    CleanupDevice();
    return 0;
    }

    // Инициализация матриц
    if( FAILED( InitMatrixes() ) )
    {
    MessageBox(0, L"Direct matrix init failed",
    L"Error", MB_OK);
    CleanupDevice();
    return 0;
    }

    if (!InitDirectInput(hInstance))
    {
    MessageBox(0, L"Direct Input Initialization - Failed",
    L"Error", MB_OK);
    CleanupDevice();
    return 0;
    }

    // Главный цикл сообщений
    MSG msg = {0};
    while( WM_QUIT != msg.message )
    {
    if( PeekMessage( &msg, NULL, 0, 0, PM_REMOVE ) )
    {
    TranslateMessage( &msg );
    DispatchMessage( &msg );
    }
    else
    {
    Render(); // Рисуем сцену
    }
    }
    // Освобождаем объекты DirectX
    CleanupDevice();

    return ( int )msg.wParam;
    }

    //--------------------------------------------------------------------------------------
    // Создание инпутов
    //--------------------------------------------------------------------------------------
    bool InitDirectInput(HINSTANCE hInstance)
    {
    HRESULT hr;
    hr = DirectInput8Create(hInstance,
    DIRECTINPUT_VERSION,
    IID_IDirectInput8,
    (void**)&DirectInput,
    NULL);

    hr = DirectInput->CreateDevice(GUID_SysKeyboard,
    &DIKeyboard,
    NULL);



    hr = DIKeyboard->SetDataFormat(&c_dfDIKeyboard);
    hr = DIKeyboard->SetCooperativeLevel(g_hWnd, DISCL_FOREGROUND | DISCL_NONEXCLUSIVE);

    return true;
    }

    void DetectInput(double time)
    {
    float speed = 0.001f;
    /*movX1 = 0.0f;
    movX2 = 0;
    movY1 = 0;
    movY2 = 0;*/

    BYTE keyboardState[256];

    DIKeyboard->Acquire();

    DIKeyboard->GetDeviceState(sizeof(keyboardState), (LPVOID)&keyboardState);


    /*if (keyboardState[DIK_ESCAPE] & 0x80)
    PostMessage(g_hWnd, WM_DESTROY, 0, 0);*/

    if (keyboardState[DIK_LEFT] & 0x80)
    {
    movX1 -= speed * time;
    }
    if (keyboardState[DIK_RIGHT] & 0x80)
    {
    movX1 += speed * time;
    }
    if (keyboardState[DIK_UP] & 0x80)
    {
    movY1 += speed * time;
    }
    if (keyboardState[DIK_DOWN] & 0x80)
    {
    movY1 -= speed * time;
    }

    if (keyboardState[DIK_A] & 0x80)
    {
    movX2 -= speed * time;
    }
    if (keyboardState[DIK_D] & 0x80)
    {
    movX2 += speed * time;
    }
    if (keyboardState[DIK_W] & 0x80)
    {
    movY2 += speed * time;
    }
    if (keyboardState[DIK_S] & 0x80)
    {
    movY2 -= speed * time;
    }

    return;
    }


    //--------------------------------------------------------------------------------------
    // Регистрация класса и создание окна
    //--------------------------------------------------------------------------------------
    HRESULT InitWindow( HINSTANCE hInstance, int nCmdShow )
    {
    // Регистрация класса
    WNDCLASSEX wcex;
    wcex.cbSize = sizeof( WNDCLASSEX );
    wcex.style = CS_HREDRAW | CS_VREDRAW;
    wcex.lpfnWndProc = WndProc;
    wcex.cbClsExtra = 0;
    wcex.cbWndExtra = 0;
    wcex.hInstance = hInstance;
    wcex.hIcon = LoadIcon( hInstance, ( LPCTSTR )IDI_ICON1 );
    wcex.hCursor = LoadCursor( NULL, IDC_ARROW );
    wcex.hbrBackground = ( HBRUSH )( COLOR_WINDOW + 1 );
    wcex.lpszMenuName = NULL;
    wcex.lpszClassName = L"CG4";
    wcex.hIconSm = LoadIcon( wcex.hInstance, ( LPCTSTR )IDI_ICON1 );
    if( !RegisterClassEx( &wcex ) )
    return E_FAIL;

    // Создание окна
    g_hInst = hInstance;
    RECT rc = { 0, 0, 400, 300 };
    AdjustWindowRect( &rc, WS_OVERLAPPEDWINDOW, FALSE );
    g_hWnd = CreateWindow( L"CG4", L"CG", WS_OVERLAPPEDWINDOW,
    CW_USEDEFAULT, CW_USEDEFAULT, rc.right - rc.left, rc.bottom - rc.top, NULL, NULL, hInstance,
    NULL );
    if( !g_hWnd )
    return E_FAIL;

    ShowWindow( g_hWnd, nCmdShow );

    return S_OK;
    }


    //--------------------------------------------------------------------------------------
    // Вызывается каждый раз, когда приложение получает системное сообщение
    //--------------------------------------------------------------------------------------
    LRESULT CALLBACK WndProc( HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam )
    {
    PAINTSTRUCT ps;
    HDC hdc;

    switch( message )
    {
    case WM_PAINT:
    hdc = BeginPaint( hWnd, &ps );
    EndPaint( hWnd, &ps );
    break;

    case WM_DESTROY:
    PostQuitMessage( 0 );
    break;

    default:
    return DefWindowProc( hWnd, message, wParam, lParam );
    }

    return 0;
    }


    //--------------------------------------------------------------------------------------
    // Вспомогательная функция для компиляции шейдеров в D3DX11
    //--------------------------------------------------------------------------------------
    HRESULT CompileShaderFromFile( WCHAR* szFileName, LPCSTR szEntryPoint, LPCSTR szShaderModel, ID3DBlob** ppBlobOut )
    {
    HRESULT hr = S_OK;

    DWORD dwShaderFlags = D3DCOMPILE_ENABLE_STRICTNESS;
    ID3DBlob* pErrorBlob;
    hr = D3DX11CompileFromFile( szFileName, NULL, NULL, szEntryPoint, szShaderModel,
    dwShaderFlags, 0, NULL, ppBlobOut, &pErrorBlob, NULL );
    if( FAILED(hr) )
    {
    if( pErrorBlob != NULL )
    OutputDebugStringA( (char*)pErrorBlob->GetBufferPointer() );
    if( pErrorBlob ) pErrorBlob->Release();
    return hr;
    }
    if( pErrorBlob ) pErrorBlob->Release();

    return S_OK;
    }


    //--------------------------------------------------------------------------------------
    // Создание устройства Direct3D (D3D Device), связующей цепи (Swap Chain) и
    // контекста устройства (Immediate Context).
    //--------------------------------------------------------------------------------------
    HRESULT InitDevice()
    {
    HRESULT hr = S_OK;

    RECT rc;
    GetClientRect( g_hWnd, &rc );
    UINT width = rc.right - rc.left; // получаем ширину
    UINT height = rc.bottom - rc.top; // и высоту окна

    UINT createDeviceFlags = 0;
    #ifdef _DEBUG
    createDeviceFlags |= D3D11_CREATE_DEVICE_DEBUG;
    #endif

    D3D_DRIVER_TYPE driverTypes[] =
    {
    D3D_DRIVER_TYPE_HARDWARE,
    D3D_DRIVER_TYPE_WARP,
    D3D_DRIVER_TYPE_REFERENCE,
    };
    UINT numDriverTypes = ARRAYSIZE( driverTypes );

    // Тут мы создаем список поддерживаемых версий DirectX
    D3D_FEATURE_LEVEL featureLevels[] =
    {
    D3D_FEATURE_LEVEL_11_0,
    D3D_FEATURE_LEVEL_10_1,
    D3D_FEATURE_LEVEL_10_0,
    };
    UINT numFeatureLevels = ARRAYSIZE( featureLevels );

    // Сейчас мы создадим устройства DirectX. Для начала заполним структуру,
    // которая описывает свойства переднего буфера и привязывает его к нашему окну.
    DXGI_SWAP_CHAIN_DESC sd; // Структура, описывающая цепь связи (Swap Chain)
    ZeroMemory( &sd, sizeof( sd ) ); // очищаем ее
    sd.BufferCount = 1; // у нас один буфер
    sd.BufferDesc.Width = width; // ширина буфера
    sd.BufferDesc.Height = height; // высота буфера
    sd.BufferDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM; // формат пикселя в буфере
    sd.BufferDesc.RefreshRate.Numerator = 75; // частота обновления экрана
    sd.BufferDesc.RefreshRate.Denominator = 1;
    sd.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT; // назначение буфера - задний буфер
    sd.OutputWindow = g_hWnd; // привязываем к нашему окну
    sd.SampleDesc.Count = 1;
    sd.SampleDesc.Quality = 0;
    sd.Windowed = TRUE; // не полноэкранный режим

    for( UINT driverTypeIndex = 0; driverTypeIndex < numDriverTypes; driverTypeIndex++ )
    {
    g_driverType = driverTypes[driverTypeIndex];
    hr = D3D11CreateDeviceAndSwapChain( NULL, g_driverType, NULL, createDeviceFlags, featureLevels, numFeatureLevels,
    D3D11_SDK_VERSION, &sd, &g_pSwapChain, &g_pd3dDevice, &g_featureLevel, &g_pImmediateContext );
    if (SUCCEEDED(hr)) // Если устройства созданы успешно, то выходим из цикла
    break;
    }
    if (FAILED(hr)) return hr;

    // Теперь создаем задний буфер. Обратите внимание, в SDK
    // RenderTargetOutput - это передний буфер, а RenderTargetView - задний.
    // Извлекаем описание заднего буфера
    ID3D11Texture2D* pBackBuffer = NULL;
    hr = g_pSwapChain->GetBuffer( 0, __uuidof( ID3D11Texture2D ), ( LPVOID* )&pBackBuffer );
    if (FAILED(hr)) return hr;

    // По полученному описанию создаем поверхность рисования
    hr = g_pd3dDevice->CreateRenderTargetView( pBackBuffer, NULL, &g_pRenderTargetView );
    pBackBuffer->Release();
    if (FAILED(hr)) return hr;

    // Переходим к созданию буфера глубин
    // Создаем текстуру-описание буфера глубин
    D3D11_TEXTURE2D_DESC descDepth; // Структура с параметрами
    ZeroMemory( &descDepth, sizeof(descDepth) );
    descDepth.Width = width; // ширина и
    descDepth.Height = height; // высота текстуры
    descDepth.MipLevels = 1; // уровень интерполяции
    descDepth.ArraySize = 1;
    descDepth.Format = DXGI_FORMAT_D24_UNORM_S8_UINT; // формат (размер пикселя)
    descDepth.SampleDesc.Count = 1;
    descDepth.SampleDesc.Quality = 0;
    descDepth.Usage = D3D11_USAGE_DEFAULT;
    descDepth.BindFlags = D3D11_BIND_DEPTH_STENCIL; // вид - буфер глубин
    descDepth.CPUAccessFlags = 0;
    descDepth.MiscFlags = 0;
    // При помощи заполненной структуры-описания создаем объект текстуры
    hr = g_pd3dDevice->CreateTexture2D( &descDepth, NULL, &g_pDepthStencil );
    if (FAILED(hr)) return hr;

    // Теперь надо создать сам объект буфера глубин
    D3D11_DEPTH_STENCIL_VIEW_DESC descDSV; // Структура с параметрами
    ZeroMemory( &descDSV, sizeof(descDSV) );
    descDSV.Format = descDepth.Format; // формат как в текстуре
    descDSV.ViewDimension = D3D11_DSV_DIMENSION_TEXTURE2D;
    descDSV.Texture2D.MipSlice = 0;
    // При помощи заполненной структуры-описания и текстуры создаем объект буфера глубин
    hr = g_pd3dDevice->CreateDepthStencilView( g_pDepthStencil, &descDSV, &g_pDepthStencilView );
    if (FAILED(hr)) return hr;

    // Подключаем объект заднего буфера и объект буфера глубин к контексту устройства
    g_pImmediateContext->OMSetRenderTargets( 1, &g_pRenderTargetView, g_pDepthStencilView );

    // Установки вьюпорта (масштаб и система координат). В предыдущих версиях он создавался
    // автоматически, если не был задан явно.
    D3D11_VIEWPORT vp;
    vp.Width = (FLOAT)width ;
    vp.Height = (FLOAT)height ;
    vp.MinDepth = 0.0f;
    vp.MaxDepth = 1.0f;
    vp.TopLeftX = 0;
    vp.TopLeftY = 0;
    g_pImmediateContext->RSSetViewports( 1, &vp );

    return S_OK;
    }


    //--------------------------------------------------------------------------------------
    // Создание буфера вершин, шейдеров (shaders) и описания формата вершин (input layout)
    //--------------------------------------------------------------------------------------
    HRESULT InitGeometry()
    {
    HRESULT hr = S_OK;

    // Компиляция вершинного шейдера из файла
    ID3DBlob* pVSBlob = NULL; // Вспомогательный объект - просто место в оперативной памяти
    hr = CompileShaderFromFile( L"urok5.fx", "VS", "vs_4_0", &pVSBlob );
    if( FAILED( hr ) )
    {
    MessageBox( NULL, L"Невозможно скомпилировать файл FX. Пожалуйста, запустите данную программу из папки, содержащей файл FX.", L"Ошибка", MB_OK );
    return hr;
    }

    // Создание вершинного шейдера
    hr = g_pd3dDevice->CreateVertexShader( pVSBlob->GetBufferPointer(), pVSBlob->GetBufferSize(), NULL, &g_pVertexShader );
    if( FAILED( hr ) )
    {
    pVSBlob->Release();
    return hr;
    }

    // Определение шаблона вершин
    D3D11_INPUT_ELEMENT_DESC layout[] =
    {
    { "POSITION", 0, DXGI_FORMAT_R32G32B32_FLOAT, 0, 0, D3D11_INPUT_PER_VERTEX_DATA, 0 },
    { "NORMAL", 0, DXGI_FORMAT_R32G32B32_FLOAT, 0, 12, D3D11_INPUT_PER_VERTEX_DATA, 0 },
    };
    UINT numElements = ARRAYSIZE( layout );

    // Создание шаблона вершин
    hr = g_pd3dDevice->CreateInputLayout( layout, numElements, pVSBlob->GetBufferPointer(),
    pVSBlob->GetBufferSize(), &g_pVertexLayout );
    pVSBlob->Release();
    if (FAILED(hr)) return hr;

    // Подключение шаблона вершин
    g_pImmediateContext->IASetInputLayout( g_pVertexLayout );

    // Компиляция пиксельного шейдера для основного большого куба из файла
    ID3DBlob* pPSBlob = NULL;
    hr = CompileShaderFromFile( L"urok5.fx", "Diffuse", "ps_4_0", &pPSBlob );
    if( FAILED( hr ) )
    {
    MessageBox( NULL, L"Невозможно скомпилировать файл FX. Пожалуйста, запустите данную программу из папки, содержащей файл FX.", L"Ошибка", MB_OK );
    return hr;
    }

    // Создание пиксельного шейдера
    hr = g_pd3dDevice->CreatePixelShader( pPSBlob->GetBufferPointer(), pPSBlob->GetBufferSize(), NULL, &g_pPixelShader );
    pPSBlob->Release();
    if (FAILED(hr))
    return hr;

    // Компиляция пиксельного шейдера для источников света из файла
    pPSBlob = NULL;
    hr = CompileShaderFromFile( L"urok5.fx", "PSSolid", "ps_4_0", &pPSBlob );
    if( FAILED( hr ) )
    {
    MessageBox( NULL, L"Невозможно скомпилировать файл FX. Пожалуйста, запустите данную программу из папки, содержащей файл FX.", L"Ошибка", MB_OK );
    return hr;
    }

    // Создание пиксельного шейдера
    hr = g_pd3dDevice->CreatePixelShader( pPSBlob->GetBufferPointer(), pPSBlob->GetBufferSize(), NULL, &g_pPixelShaderSolid );
    pPSBlob->Release();
    if (FAILED(hr)) return hr;

    // Компиляция пиксельного шейдера для основного большого куба из файла
    ID3DBlob* pPSBlob2 = NULL;
    hr = CompileShaderFromFile(L"urok5.fx", "Specular", "ps_4_0", &pPSBlob2);
    if (FAILED(hr))
    {
    MessageBox(NULL, L"Невозможно скомпилировать файл FX. Пожалуйста, запустите данную программу из папки, содержащей файл FX.", L"Ошибка", MB_OK);
    return hr;
    }

    // Создание пиксельного шейдера
    hr = g_pd3dDevice->CreatePixelShader(pPSBlob2->GetBufferPointer(), pPSBlob2->GetBufferSize(), NULL, &g_pPixelShader2);
    pPSBlob2->Release();
    if (FAILED(hr))
    return hr;


    // Создание буфера вершин (по 4 точки на каждую сторону куба, всего 24 вершины)
    SimpleVertex vertices[] =
    { /* координаты X, Y, Z нормаль X, Y, Z */
    { XMFLOAT3( -1.0f, 1.0f, -1.0f ), XMFLOAT3( 0.0f, 1.0f, 0.0f ) },
    { XMFLOAT3( 1.0f, 1.0f, -1.0f ), XMFLOAT3( 0.0f, 1.0f, 0.0f ) },
    { XMFLOAT3( 1.0f, 1.0f, 1.0f ), XMFLOAT3( 0.0f, 1.0f, 0.0f ) },
    { XMFLOAT3( -1.0f, 1.0f, 1.0f ), XMFLOAT3( 0.0f, 1.0f, 0.0f ) },

    { XMFLOAT3( -1.0f, -1.0f, -1.0f ), XMFLOAT3( 0.0f, -1.0f, 0.0f ) },
    { XMFLOAT3( 1.0f, -1.0f, -1.0f ), XMFLOAT3( 0.0f, -1.0f, 0.0f ) },
    { XMFLOAT3( 1.0f, -1.0f, 1.0f ), XMFLOAT3( 0.0f, -1.0f, 0.0f ) },
    { XMFLOAT3( -1.0f, -1.0f, 1.0f ), XMFLOAT3( 0.0f, -1.0f, 0.0f ) },

    { XMFLOAT3( -1.0f, -1.0f, 1.0f ), XMFLOAT3( -1.0f, 0.0f, 0.0f ) },
    { XMFLOAT3( -1.0f, -1.0f, -1.0f ), XMFLOAT3( -1.0f, 0.0f, 0.0f ) },
    { XMFLOAT3( -1.0f, 1.0f, -1.0f ), XMFLOAT3( -1.0f, 0.0f, 0.0f ) },
    { XMFLOAT3( -1.0f, 1.0f, 1.0f ), XMFLOAT3( -1.0f, 0.0f, 0.0f ) },

    { XMFLOAT3( 1.0f, -1.0f, 1.0f ), XMFLOAT3( 1.0f, 0.0f, 0.0f ) },
    { XMFLOAT3( 1.0f, -1.0f, -1.0f ), XMFLOAT3( 1.0f, 0.0f, 0.0f ) },
    { XMFLOAT3( 1.0f, 1.0f, -1.0f ), XMFLOAT3( 1.0f, 0.0f, 0.0f ) },
    { XMFLOAT3( 1.0f, 1.0f, 1.0f ), XMFLOAT3( 1.0f, 0.0f, 0.0f ) },

    { XMFLOAT3( -1.0f, -1.0f, -1.0f ), XMFLOAT3( 0.0f, 0.0f, -1.0f ) },
    { XMFLOAT3( 1.0f, -1.0f, -1.0f ), XMFLOAT3( 0.0f, 0.0f, -1.0f ) },
    { XMFLOAT3( 1.0f, 1.0f, -1.0f ), XMFLOAT3( 0.0f, 0.0f, -1.0f ) },
    { XMFLOAT3( -1.0f, 1.0f, -1.0f ), XMFLOAT3( 0.0f, 0.0f, -1.0f ) },

    { XMFLOAT3( -1.0f, -1.0f, 1.0f ), XMFLOAT3( 0.0f, 0.0f, 1.0f ) },
    { XMFLOAT3( 1.0f, -1.0f, 1.0f ), XMFLOAT3( 0.0f, 0.0f, 1.0f ) },
    { XMFLOAT3( 1.0f, 1.0f, 1.0f ), XMFLOAT3( 0.0f, 0.0f, 1.0f ) },
    { XMFLOAT3( -1.0f, 1.0f, 1.0f ), XMFLOAT3( 0.0f, 0.0f, 1.0f ) },
    };

    D3D11_BUFFER_DESC bd; // Структура, описывающая создаваемый буфер
    ZeroMemory( &bd, sizeof(bd) ); // очищаем ее
    bd.Usage = D3D11_USAGE_DEFAULT;
    bd.ByteWidth = sizeof( SimpleVertex ) * 24; // размер буфера
    bd.BindFlags = D3D11_BIND_VERTEX_BUFFER; // тип буфера - буфер вершин
    bd.CPUAccessFlags = 0;
    D3D11_SUBRESOURCE_DATA InitData; // Структура, содержащая данные буфера
    ZeroMemory( &InitData, sizeof(InitData) ); // очищаем ее
    InitData.pSysMem = vertices; // указатель на наши 8 вершин
    hr = g_pd3dDevice->CreateBuffer( &bd, &InitData, &g_pVertexBuffer );
    if (FAILED(hr)) return hr;

    // Создание буфера индексов
    // 1) cоздание массива с данными
    WORD indices[] =
    {
    3,1,0,
    2,1,3,

    6,4,5,
    7,4,6,

    11,9,8,
    10,9,11,

    14,12,13,
    15,12,14,

    19,17,16,
    18,17,19,

    22,20,21,
    23,20,22
    };
    // 2) cоздание объекта буфера
    bd.Usage = D3D11_USAGE_DEFAULT; // Структура, описывающая создаваемый буфер
    bd.ByteWidth = sizeof( WORD ) * 36; // 36 вершин для 12 треугольников (6 сторон)
    bd.BindFlags = D3D11_BIND_INDEX_BUFFER; // тип - буфер индексов
    bd.CPUAccessFlags = 0;
    InitData.pSysMem = indices; // указатель на наш массив индексов
    // Вызов метода g_pd3dDevice создаст объект буфера индексов
    hr = g_pd3dDevice->CreateBuffer( &bd, &InitData, &g_pIndexBuffer );
    if (FAILED(hr)) return hr;

    // Установка буфера вершин
    UINT stride = sizeof( SimpleVertex );
    UINT offset = 0;
    g_pImmediateContext->IASetVertexBuffers( 0, 1, &g_pVertexBuffer, &stride, &offset );
    // Установка буфера индексов
    g_pImmediateContext->IASetIndexBuffer( g_pIndexBuffer, DXGI_FORMAT_R16_UINT, 0 );
    // Установка способа отрисовки вершин в буфере
    g_pImmediateContext->IASetPrimitiveTopology( D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST );

    // Создание константного буфера
    bd.Usage = D3D11_USAGE_DEFAULT;
    bd.ByteWidth = sizeof(ConstantBuffer); // размер буфера = размеру структуры
    bd.BindFlags = D3D11_BIND_CONSTANT_BUFFER; // тип - константный буфер
    bd.CPUAccessFlags = 0;
    hr = g_pd3dDevice->CreateBuffer( &bd, NULL, &g_pConstantBuffer );
    if (FAILED(hr)) return hr;

    return S_OK;
    }


    //--------------------------------------------------------------------------------------
    // Инициализация матриц
    //--------------------------------------------------------------------------------------
    HRESULT InitMatrixes()
    {
    RECT rc;
    GetClientRect( g_hWnd, &rc );
    UINT width = rc.right - rc.left; // получаем ширину
    UINT height = rc.bottom - rc.top; // и высоту окна

    // Инициализация матрицы мира
    g_World = XMMatrixIdentity();

    // Инициализация матрицы вида
    XMVECTOR EyePos = XMLoadFloat4(&Eye); // Откуда смотрим
    XMVECTOR At = XMVectorSet( 0.0f, 1.0f, 0.0f, 0.0f ); // Куда смотрим
    XMVECTOR Up = XMVectorSet( 0.0f, 1.0f, 0.0f, 0.0f ); // Направление верха
    g_View = XMMatrixLookAtLH(EyePos, At, Up);

    // Инициализация матрицы проекции
    // Параметры: 1) ширина угла объектива 2) "квадратность" пикселя
    // 3) самое ближнее видимое расстояние 4) самое дальнее видимое расстояние
    g_Projection = XMMatrixPerspectiveFovLH( XM_PIDIV4, width / (FLOAT)height, 0.01f, 100.0f );

    return S_OK;
    }

    //--------------------------------------------------------------------------------------
    // Вычисляем направление света
    //--------------------------------------------------------------------------------------
    void UpdateLight()
    {
    // Обновление переменной-времени
    if( g_driverType == D3D_DRIVER_TYPE_REFERENCE )
    {
    t += ( float )XM_PI * 0.0125f;
    }
    else
    {
    static DWORD dwTimeStart = 0;
    DWORD dwTimeCur = GetTickCount();
    if( dwTimeStart == 0 )
    dwTimeStart = dwTimeCur;
    t = ( dwTimeCur - dwTimeStart ) / 1000.0f;
    }
    DetectInput(t);
    // Задаем начальные координаты источников света
    //vLightDirs[0] = XMFLOAT4( -0.577f, 0.577f, -0.577f, 1.0f );
    vLightDirs[0] = XMFLOAT4( 1.0f, 0.0f, 1.577f, 1.0f );
    vLightDirs[1] = XMFLOAT4( 0.0f, 0.0f, -1.0f, 1.0f );
    vLightDirs[2] = XMFLOAT4( 0.0f, 0.0f, -2.0f, 1.0f);
    // Задаем цвет источников света
    vLightColors[0] = XMFLOAT4(1.0f, 1.0f, 1.0f, 1.0f);
    vLightColors[1] = XMFLOAT4( 0.0f, 0.0f, 1.0f, 1.0f );
    vLightColors[2] = XMFLOAT4( 1.0f, 0.0f, 0.0f, 1.0f);


    XMMATRIX mRotate = XMMatrixRotationY( -2.0f * t );
    XMVECTOR vLightDir = XMLoadFloat4( &vLightDirs[1] );
    vLightDir = XMVector3Transform( vLightDir, mRotate );
    XMStoreFloat4( &vLightDirs[1], vLightDir );

    mRotate = XMMatrixRotationY( 0.5f * t );
    vLightDir = XMLoadFloat4( &vLightDirs[0] );
    vLightDir = XMVector3Transform( vLightDir, mRotate );
    XMStoreFloat4( &vLightDirs[0], vLightDir );


    mRotate = XMMatrixRotationX(1.0f * t);
    vLightDir = XMLoadFloat4(&vLightDirs[2]);
    vLightDir = XMVector3Transform(vLightDir, mRotate);
    XMStoreFloat4(&vLightDirs[2], vLightDir);
    }

    //--------------------------------------------------------------------------------------
    // Устанавливаем матрицы для текущего источника света (0-1) или мира (MX_SETWORLD)
    //--------------------------------------------------------------------------------------
    void UpdateMatrix(UINT nLightIndex)
    {
    // Небольшая проверка индекса
    if (nLightIndex == MX_SETWORLD) {
    // Если рисуем центральный куб: его надо просто медленно вращать
    g_World = XMMatrixRotationAxis(XMVectorSet(1.0f, 1.0f, 0.0f, 0.0f), t) *XMMatrixTranslation(movX2, movY2, 0.0f);
    nLightIndex = 0;
    }
    else if (nLightIndex == MX_SETWORLD2) {

    g_World = XMMatrixTranslation(movX1, movY1, 0.0f) * XMMatrixTranslation(-3.0f, 0.0f, 0.0f);
    nLightIndex = 0;
    }
    else if (nLightIndex < 3) {
    // Если рисуем источники света: перемещаем матрицу в точку и уменьшаем в 5 раз
    g_World = XMMatrixTranslationFromVector( 5.0f * XMLoadFloat4( &vLightDirs[nLightIndex] ) );
    XMMATRIX mLightScale = XMMatrixScaling( 0.4f, 0.4f, 0.4f );
    g_World = mLightScale * g_World;
    }
    else {
    nLightIndex = 0;
    }

    // Обновление содержимого константного буфера
    ConstantBuffer cb1; // временный контейнер
    cb1.mWorld = XMMatrixTranspose( g_World ); // загружаем в него матрицы
    cb1.mView = XMMatrixTranspose( g_View );
    cb1.mProjection = XMMatrixTranspose( g_Projection );
    cb1.vLightDir[0] = vLightDirs[0]; // загружаем данные о свете
    cb1.vLightDir[1] = vLightDirs[1];
    cb1.vLightDir[2] = vLightDirs[2];
    cb1.vLightColor[0] = vLightColors[0];
    cb1.vLightColor[1] = vLightColors[1];
    cb1.vLightColor[2] = vLightColors[2];

    cb1.vOutputColor = vLightColors[nLightIndex];
    g_pImmediateContext->UpdateSubresource( g_pConstantBuffer, 0, NULL, &cb1, 0, 0 );
    }


    //--------------------------------------------------------------------------------------
    // Рендеринг кадра
    //--------------------------------------------------------------------------------------
    void Render()
    {
    // Очищаем задний буфер
    float ClearColor[4] = { 0.0f, 0.0f, 0.0f, 1.0f };
    g_pImmediateContext->ClearRenderTargetView( g_pRenderTargetView, ClearColor );
    // Очищаем буфер глубин до едицины (максимальная глубина)
    g_pImmediateContext->ClearDepthStencilView( g_pDepthStencilView, D3D11_CLEAR_DEPTH, 1.0f, 0 );

    UpdateLight(); // Устанвока освещения



    UpdateMatrix(MX_SETWORLD);
    g_pImmediateContext->VSSetShader( g_pVertexShader, NULL, 0 );
    g_pImmediateContext->VSSetConstantBuffers( 0, 1, &g_pConstantBuffer );
    g_pImmediateContext->PSSetShader( g_pPixelShader, NULL, 0 );
    g_pImmediateContext->PSSetConstantBuffers(0, 1, &g_pConstantBuffer);
    g_pImmediateContext->DrawIndexed( 36, 0, 0 );

    UpdateMatrix(MX_SETWORLD2);

    g_pImmediateContext->VSSetShader(g_pVertexShader, NULL, 0);
    g_pImmediateContext->VSSetConstantBuffers(0, 1, &g_pConstantBuffer);
    g_pImmediateContext->PSSetShader(g_pPixelShader2, NULL, 0);
    g_pImmediateContext->PSSetConstantBuffers(0, 1, &g_pConstantBuffer);
    g_pImmediateContext->DrawIndexed(36, 0, 0);

    g_pImmediateContext->PSSetShader( g_pPixelShaderSolid, NULL, 0 );
    for( int m = 0; m < 3; m++ )
    {
    // 2) Устанавливаем матрицу мира источника света
    UpdateMatrix( m );
    // 3) Рисуем в заднем буфере 36 вершин
    g_pImmediateContext->DrawIndexed( 36, 0, 0 );
    }

    // Копируем задний буфер в переднйи (на экран)
    g_pSwapChain->Present( 0, 0 );
    }


    //--------------------------------------------------------------------------------------
    // Освобождение всех созданных объектов
    //--------------------------------------------------------------------------------------
    void CleanupDevice()
    {
    // Сначала отключим контекст устройства
    if( g_pImmediateContext ) g_pImmediateContext->ClearState();
    // Потом удалим объекты
    if( g_pConstantBuffer ) g_pConstantBuffer->Release();
    if( g_pVertexBuffer ) g_pVertexBuffer->Release();
    if( g_pIndexBuffer ) g_pIndexBuffer->Release();
    if( g_pVertexLayout ) g_pVertexLayout->Release();
    if( g_pVertexShader ) g_pVertexShader->Release();
    if( g_pPixelShaderSolid ) g_pPixelShaderSolid->Release();
    if( g_pPixelShader ) g_pPixelShader->Release();
    if( g_pDepthStencil ) g_pDepthStencil->Release();
    if( g_pDepthStencilView ) g_pDepthStencilView->Release();
    if( g_pRenderTargetView ) g_pRenderTargetView->Release();
    if( g_pSwapChain ) g_pSwapChain->Release();
    if( g_pImmediateContext ) g_pImmediateContext->Release();
    if( g_pd3dDevice ) g_pd3dDevice->Release();
    if (DirectInput) DirectInput->Release();
    if (DIKeyboard) DIKeyboard->Unacquire();
    }