Created
          May 21, 2019 14:06 
        
      - 
      
- 
        Save rdeioris/23278848591e2feb9c17a5dc6ea49a1e 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
    
  
  
    
  | #include <iostream> | |
| #include <string> | |
| #include <Windows.h> | |
| #include <dxgi1_6.h> | |
| #include <d3d11_4.h> | |
| #define STB_IMAGE_IMPLEMENTATION | |
| #include "stb_image.h" | |
| #include "vs001.h" | |
| #include "ps001.h" | |
| #include <Xinput.h> | |
| namespace aiv | |
| { | |
| void DieBadly(std::string message) | |
| { | |
| MessageBox(nullptr, message.c_str(), nullptr, MB_OK); | |
| std::exit(-1); | |
| } | |
| } | |
| int main(int argc, char **argv) | |
| { | |
| // create a DXGI factory, required for operating system | |
| // integration, like enumerating adapters and creating swap chains | |
| IDXGIFactory2* factory = nullptr; | |
| if (CreateDXGIFactory2(0, __uuidof(IDXGIFactory2), (void **)&factory) != S_OK) | |
| { | |
| aiv::DieBadly("unable to create factory"); | |
| } | |
| // find the best adapter (hardware and max dedicated unshared memory) | |
| UINT i = 0; | |
| IDXGIAdapter1* adapter = nullptr; | |
| IDXGIAdapter1* best_adapter = nullptr; | |
| SIZE_T best_memory = 0; | |
| // enum adapters returns DXGI_ERROR_NOT_FOUND if the specified index | |
| // does not exist | |
| while (factory->EnumAdapters1(i++, &adapter) != DXGI_ERROR_NOT_FOUND) | |
| { | |
| DXGI_ADAPTER_DESC1 desc; | |
| if (adapter->GetDesc1(&desc) != S_OK) | |
| { | |
| aiv::DieBadly("unable to get adapter description"); | |
| } | |
| std::wcout << desc.Description << " " << desc.DedicatedVideoMemory << std::endl; | |
| if (desc.Flags == DXGI_ADAPTER_FLAG_NONE && desc.DedicatedVideoMemory > best_memory) | |
| { | |
| best_memory = desc.DedicatedVideoMemory; | |
| best_adapter = adapter; | |
| } | |
| } | |
| if (!best_adapter) | |
| { | |
| aiv::DieBadly("unable to find a valid adapter"); | |
| } | |
| ID3D11Device5* device = nullptr; | |
| ID3D11DeviceContext4* context = nullptr; | |
| // this is the list of features we want to support | |
| D3D_FEATURE_LEVEL feature_levels[] = { | |
| D3D_FEATURE_LEVEL_11_1, | |
| D3D_FEATURE_LEVEL_11_0, | |
| }; | |
| // this will be filled with the selected feature level | |
| D3D_FEATURE_LEVEL feature_level; | |
| // a device is a logical representation of an adapter, allowed to create objects | |
| // (buffers, textures, shaders, ...) in the gpu. | |
| // a context is a channel for issuing commands | |
| if (D3D11CreateDevice(best_adapter, D3D_DRIVER_TYPE_UNKNOWN, | |
| nullptr, 0, feature_levels, _countof(feature_levels), D3D11_SDK_VERSION, | |
| (ID3D11Device**)&device, &feature_level, (ID3D11DeviceContext**)&context) != S_OK) | |
| { | |
| aiv::DieBadly("unable to create device and context"); | |
| } | |
| // create a win32 window class (required for creating windows) | |
| WNDCLASS wclass = {}; | |
| wclass.lpszClassName = "dx11_window_class"; | |
| wclass.hInstance = GetModuleHandle(nullptr); | |
| wclass.lpfnWndProc = DefWindowProc; | |
| RegisterClass(&wclass); | |
| // the window size is cutted by the border/caption size, so | |
| // we need to compute the right window size for having | |
| // a drawable area of 1024x1024 | |
| int width = 1024; | |
| int height = 1024; | |
| DWORD style = WS_OVERLAPPEDWINDOW; | |
| RECT rect = { 0, 0, width, height }; | |
| // this will compute the right dimension | |
| AdjustWindowRect(&rect, style, false); | |
| HWND window = CreateWindow(wclass.lpszClassName, "D3D11", | |
| style, CW_USEDEFAULT, CW_USEDEFAULT, | |
| rect.right - rect.left, rect.bottom - rect.top, nullptr, nullptr, wclass.hInstance, nullptr); | |
| // prepare the swap chain configuration | |
| DXGI_SWAP_CHAIN_DESC1 sc_desc = {}; | |
| sc_desc.BufferCount = 1; | |
| sc_desc.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT; | |
| sc_desc.Format = DXGI_FORMAT_R8G8B8A8_UNORM; | |
| sc_desc.Width = width; | |
| sc_desc.Height = height; | |
| sc_desc.SwapEffect = DXGI_SWAP_EFFECT_DISCARD; | |
| sc_desc.SampleDesc.Count = 1; | |
| sc_desc.SampleDesc.Quality = 0; | |
| IDXGISwapChain1* swap_chain = nullptr; | |
| if (factory->CreateSwapChainForHwnd(device, window, &sc_desc, nullptr, nullptr, &swap_chain) != S_OK) | |
| { | |
| aiv::DieBadly("unable to create swap chain"); | |
| } | |
| // retrieve the texture mapped to the swap chain | |
| ID3D11Texture2D* swap_chain_texture = nullptr; | |
| if (swap_chain->GetBuffer(0, __uuidof(ID3D11Texture2D), (void **)&swap_chain_texture)) | |
| { | |
| aiv::DieBadly("unable to get texture from swap chain"); | |
| } | |
| // make the window visible (win32) | |
| ShowWindow(window, SW_SHOW); | |
| // load a texture | |
| int w, h, c; | |
| BYTE *pixels = stbi_load("D:/Users/rober/Downloads/scorpion.png", &w, &h, &c, 4); | |
| // create a new texture | |
| D3D11_TEXTURE2D_DESC tex_desc = {}; | |
| tex_desc.ArraySize = 1; | |
| tex_desc.BindFlags = D3D11_BIND_SHADER_RESOURCE; | |
| tex_desc.Format = DXGI_FORMAT_R8G8B8A8_UNORM; | |
| tex_desc.Height = h; | |
| tex_desc.Width = w; | |
| tex_desc.MipLevels = 1; | |
| tex_desc.Usage = D3D11_USAGE_DEFAULT; | |
| tex_desc.SampleDesc.Count = 1; | |
| tex_desc.SampleDesc.Quality = 0; | |
| // a subresource contains cpu data that must be uploaded to the gpu | |
| D3D11_SUBRESOURCE_DATA sr_data = {}; | |
| sr_data.pSysMem = pixels; | |
| sr_data.SysMemPitch = w * 4; // pitch is required for textures, it is the size (in bytes) of a single line | |
| ID3D11Texture2D* scorpion = nullptr; | |
| if (device->CreateTexture2D(&tex_desc, &sr_data, &scorpion) != S_OK) | |
| { | |
| aiv::DieBadly("unable to create texture"); | |
| } | |
| // a render target view is an object able to receive rasterization | |
| // output (like an opengl framebuffer) | |
| ID3D11RenderTargetView1* rtv = nullptr; | |
| if (device->CreateRenderTargetView1(swap_chain_texture, nullptr, &rtv) != S_OK) | |
| { | |
| aiv::DieBadly("unable to create render target view"); | |
| } | |
| // we have 2 buffers | |
| ID3D11Buffer* buffer001; | |
| ID3D11Buffer* buffer002; | |
| float vertices[] = { | |
| 0, 1, 0, | |
| -1, -1, 0, | |
| 1, -1, 0 | |
| }; | |
| float colors[] = { | |
| 1, 0, 0, | |
| 0, 1, 0, | |
| 1, 1, 0 | |
| }; | |
| D3D11_BUFFER_DESC buf_desc = {}; | |
| buf_desc.BindFlags = D3D11_BIND_VERTEX_BUFFER; | |
| buf_desc.ByteWidth = sizeof(vertices); | |
| buf_desc.Usage = D3D11_USAGE_DEFAULT; | |
| // like textures, but without pitching | |
| D3D11_SUBRESOURCE_DATA buf_data = {}; | |
| buf_data.pSysMem = vertices; | |
| if (device->CreateBuffer(&buf_desc, &buf_data, &buffer001) != S_OK) | |
| { | |
| aiv::DieBadly("unable to create buffer"); | |
| } | |
| // NOTE: we are reusing the same buffer description struct | |
| // changing only the required values | |
| buf_desc.ByteWidth = sizeof(colors); | |
| buf_data.pSysMem = colors; | |
| if (device->CreateBuffer(&buf_desc, &buf_data, &buffer002) != S_OK) | |
| { | |
| aiv::DieBadly("unable to create buffer"); | |
| } | |
| // input layout maps semantics to input slots (PIPPO here will consume data | |
| // from slot 0, while PLUTO will consume from slot 1) | |
| D3D11_INPUT_ELEMENT_DESC layout_desc[] = | |
| { | |
| {"PIPPO", 0, DXGI_FORMAT_R32G32B32_FLOAT, 0, 0, D3D11_INPUT_PER_VERTEX_DATA, 0}, | |
| {"PLUTO", 0, DXGI_FORMAT_R32G32B32_FLOAT, 1, 0, D3D11_INPUT_PER_VERTEX_DATA, 0}, | |
| }; | |
| // not the input layout is validated with the shader bytecode/opcodes | |
| ID3D11InputLayout* input_layout = nullptr; | |
| if (device->CreateInputLayout(layout_desc, _countof(layout_desc), vs001, sizeof(vs001), &input_layout) != S_OK) | |
| { | |
| aiv::DieBadly("invalid input layout"); | |
| } | |
| // setup IA (Input Assembly) | |
| context->IASetInputLayout(input_layout); | |
| context->IASetPrimitiveTopology(D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST); // draw triangles | |
| UINT stride = { sizeof(float) * 3 }; // how many bytes to read for each vertex | |
| UINT offset = { 0 }; | |
| // NOTE: IASetVertexBuffers takes an array of buffers, strides and offsets | |
| // but we can call it multiple times for different slots | |
| context->IASetVertexBuffers(0, 1, &buffer001, &stride, &offset); | |
| context->IASetVertexBuffers(1, 1, &buffer002, &stride, &offset); | |
| // setup VS (Vertex Shader) | |
| ID3D11VertexShader *vertex_shader = nullptr; | |
| if (device->CreateVertexShader(vs001, sizeof(vs001), nullptr, &vertex_shader) != S_OK) | |
| { | |
| aiv::DieBadly("unable to upload shader"); | |
| } | |
| context->VSSetShader(vertex_shader, nullptr, 0); | |
| // setup RS (rasterization options) | |
| ID3D11RasterizerState* rs = nullptr; | |
| D3D11_RASTERIZER_DESC rs_desc = {}; | |
| rs_desc.CullMode = D3D11_CULL_NONE; // never cull triangles | |
| rs_desc.FillMode = D3D11_FILL_SOLID; // draw solid (can be D3D11_FILL_WIREFRAME) | |
| if (device->CreateRasterizerState(&rs_desc, &rs) != S_OK) | |
| { | |
| aiv::DieBadly("unable to create rasterizer state"); | |
| } | |
| context->RSSetState(rs); | |
| // set the rendering area (viewport) | |
| D3D11_VIEWPORT viewport = {}; | |
| viewport.Height = height; | |
| viewport.Width = width; | |
| context->RSSetViewports(1, &viewport); | |
| ID3D11PixelShader *pixel_shader = nullptr; | |
| if (device->CreatePixelShader(ps001, sizeof(ps001), nullptr, &pixel_shader) != S_OK) | |
| { | |
| aiv::DieBadly("unable to upload pixel shader"); | |
| } | |
| context->PSSetShader(pixel_shader, nullptr, 0); | |
| // set the render target view | |
| context->OMSetRenderTargets(1, (ID3D11RenderTargetView **)&rtv, nullptr); | |
| while (true) | |
| { | |
| // deque and translates win32 messages | |
| MSG msg; | |
| while (PeekMessage(&msg, nullptr, 0, 0, PM_REMOVE)) | |
| { | |
| TranslateMessage(&msg); | |
| DispatchMessage(&msg); | |
| } | |
| // read xbox pad | |
| XINPUT_STATE pad = {}; | |
| XInputGetState(0, &pad); | |
| // clear the render target view with a color | |
| float blue[] = { 0, 0, 1, 1 }; | |
| context->ClearRenderTargetView(rtv, blue); | |
| //context->CopyResource(swap_chain_texture, scorpion); | |
| // draw 3 vertices using the current pipeline | |
| context->Draw(3, 0); | |
| // bit blit the back buffer to the front buffer, waiting for vsync | |
| swap_chain->Present(1, 0); | |
| } | |
| return 0; | |
| } | 
  
    Sign up for free
    to join this conversation on GitHub.
    Already have an account?
    Sign in to comment