Created
November 1, 2014 19:41
-
-
Save krupitskas/bc24880d29a0043321a1 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#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(); | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment