nuclear@3: #include nuclear@3: #include nuclear@3: #include nuclear@3: #include nuclear@3: #include nuclear@3: #include nuclear@3: nuclear@3: struct Vertex { nuclear@3: float pos[3]; nuclear@3: float color[4]; nuclear@3: }; nuclear@3: nuclear@3: struct RenderState { nuclear@3: float modelview[16]; nuclear@3: float projection[16]; nuclear@3: }; nuclear@3: nuclear@3: static bool init(); nuclear@3: static void cleanup(); nuclear@3: static void display(); nuclear@3: static void reshape(int x, int y); nuclear@3: static void keyb(int key, bool pressed); nuclear@3: static HWND create_window(int xsz, int ysz); nuclear@3: static void destroy_window(HWND win); nuclear@3: static void main_loop(); nuclear@3: static long CALLBACK win_proc(HWND win, unsigned int msg, unsigned int wparam, long lparam); nuclear@3: nuclear@3: static int width, height; nuclear@3: nuclear@3: static HWND win; nuclear@3: static IDXGISwapChain *swap; nuclear@3: static ID3D11Device *dev; nuclear@3: static ID3D11DeviceContext *ctx; nuclear@3: static ID3D11RenderTargetView *rtarg_view; nuclear@3: static ID3D11InputLayout *vertex_layout; nuclear@3: static ID3D11VertexShader *vsdr; nuclear@3: static ID3D11PixelShader *psdr; nuclear@3: static ID3D11Buffer *vbuf; nuclear@3: static ID3D11Buffer *rstate_buf; nuclear@3: nuclear@3: static RenderState rstate; nuclear@3: nuclear@3: int main() nuclear@3: { nuclear@3: if(!init()) { nuclear@3: return 1; nuclear@3: } nuclear@3: atexit(cleanup); nuclear@3: nuclear@3: main_loop(); nuclear@3: return 0; nuclear@3: } nuclear@3: nuclear@3: static bool init() nuclear@3: { nuclear@3: if(!(win = create_window(800, 600))) { nuclear@3: return false; nuclear@3: } nuclear@3: nuclear@3: unsigned int sdrflags = 0;//D3DCOMPILE_ENABLE_STRICTNESS | D3DCOMPILE_DEBUG; nuclear@3: nuclear@3: ID3DBlob *vsbuf, *psbuf, *msgblob; nuclear@3: if(D3DX11CompileFromFile("shader.hlsl", 0, 0, "vertex_main", "vs_4_0", sdrflags, 0, 0, &vsbuf, &msgblob, 0) != 0) { nuclear@3: fprintf(stderr, "failed to load vertex shader\n"); nuclear@3: if(msgblob->GetBufferSize() > 0) { nuclear@3: fprintf(stderr, "Vertex Shader:\n%s\n", (char*)msgblob->GetBufferPointer()); nuclear@3: } nuclear@3: return false; nuclear@3: } nuclear@3: if(D3DX11CompileFromFile("shader.hlsl", 0, 0, "pixel_main", "ps_4_0", sdrflags, 0, 0, &psbuf, &msgblob, 0) != 0) { nuclear@3: fprintf(stderr, "failed to load pixel shader\n"); nuclear@3: if(msgblob->GetBufferSize() > 0) { nuclear@3: fprintf(stderr, "Pixel Shader:\n%s\n", (char*)msgblob->GetBufferPointer()); nuclear@3: } nuclear@3: return false; nuclear@3: } nuclear@3: nuclear@3: if(dev->CreateVertexShader(vsbuf->GetBufferPointer(), vsbuf->GetBufferSize(), 0, &vsdr) != 0) { nuclear@3: fprintf(stderr, "failed to create vertex shader\n"); nuclear@3: return false; nuclear@3: } nuclear@3: if(dev->CreatePixelShader(psbuf->GetBufferPointer(), psbuf->GetBufferSize(), 0, &psdr) != 0) { nuclear@3: fprintf(stderr, "failed to create pixel shader\n"); nuclear@3: return false; nuclear@3: } nuclear@3: nuclear@3: D3D11_INPUT_ELEMENT_DESC elem_desc[2]; nuclear@3: elem_desc[0].SemanticName = "position"; nuclear@3: elem_desc[0].SemanticIndex = 0; nuclear@3: elem_desc[0].Format = DXGI_FORMAT_R32G32B32_FLOAT; nuclear@3: elem_desc[0].InputSlot = 0; nuclear@3: elem_desc[0].AlignedByteOffset = 0; nuclear@3: elem_desc[0].InputSlotClass = D3D11_INPUT_PER_VERTEX_DATA; nuclear@3: elem_desc[0].InstanceDataStepRate = 0; nuclear@3: nuclear@3: elem_desc[1].SemanticName = "color"; nuclear@3: elem_desc[1].SemanticIndex = 0; nuclear@3: elem_desc[1].Format = DXGI_FORMAT_R32G32B32A32_FLOAT; nuclear@3: elem_desc[1].InputSlot = 0; nuclear@3: elem_desc[1].AlignedByteOffset = offsetof(Vertex, color); nuclear@3: elem_desc[1].InputSlotClass = D3D11_INPUT_PER_VERTEX_DATA; nuclear@3: elem_desc[1].InstanceDataStepRate = 0; nuclear@3: nuclear@3: if(dev->CreateInputLayout(elem_desc, 2, vsbuf->GetBufferPointer(), vsbuf->GetBufferSize(), &vertex_layout) != 0) { nuclear@3: fprintf(stderr, "failed to create vertex layout\n"); nuclear@3: return 0; nuclear@3: } nuclear@3: vsbuf->Release(); nuclear@3: psbuf->Release(); nuclear@3: nuclear@3: // --- create vertex buffer --- nuclear@3: Vertex varr[] = { nuclear@3: {{-0.6, -0.4, 0}, {1, 0, 0, 1}}, nuclear@3: {{0.0, 0.6, 0}, {0, 1, 0, 1}}, nuclear@3: {{0.6, -0.4, 0}, {0, 0, 1, 1}} nuclear@3: }; nuclear@3: nuclear@3: D3D11_BUFFER_DESC buf_desc; nuclear@3: memset(&buf_desc, 0, sizeof buf_desc); nuclear@3: buf_desc.Usage = D3D11_USAGE_DEFAULT; nuclear@3: buf_desc.ByteWidth = sizeof varr; nuclear@3: buf_desc.BindFlags = D3D11_BIND_VERTEX_BUFFER; nuclear@3: nuclear@3: D3D11_SUBRESOURCE_DATA subdata; nuclear@3: memset(&subdata, 0, sizeof subdata); nuclear@3: subdata.pSysMem = varr; nuclear@3: if(dev->CreateBuffer(&buf_desc, &subdata, &vbuf) != 0) { nuclear@3: fprintf(stderr, "failed to create vertex buffer\n"); nuclear@3: return false; nuclear@3: } nuclear@3: nuclear@3: // render state buffer nuclear@3: memset(&buf_desc, 0, sizeof buf_desc); nuclear@3: buf_desc.Usage = D3D11_USAGE_DEFAULT; nuclear@3: buf_desc.ByteWidth = sizeof(RenderState); nuclear@3: buf_desc.BindFlags = D3D11_BIND_CONSTANT_BUFFER; nuclear@3: nuclear@3: memset(&subdata, 0, sizeof subdata); nuclear@3: subdata.pSysMem = &rstate; nuclear@3: if(dev->CreateBuffer(&buf_desc, &subdata, &rstate_buf) != 0) { nuclear@3: fprintf(stderr, "failed to create render state buffer\n"); nuclear@3: return false; nuclear@3: } nuclear@3: nuclear@3: return true; nuclear@3: } nuclear@3: nuclear@3: static void cleanup() nuclear@3: { nuclear@3: vbuf->Release(); nuclear@3: rstate_buf->Release(); nuclear@3: vsdr->Release(); nuclear@3: psdr->Release(); nuclear@3: vertex_layout->Release(); nuclear@3: destroy_window(win); nuclear@3: } nuclear@3: nuclear@3: static void set_identity(float *mat) nuclear@3: { nuclear@3: mat[0] = mat[5] = mat[10] = mat[15] = 1.0; nuclear@3: mat[1] = mat[2] = mat[3] = mat[4] = mat[6] = mat[7] = mat[8] = mat[9] = mat[11] = mat[12] = mat[13] = mat[14] = 0.0; nuclear@3: } nuclear@3: nuclear@3: static void set_rotation_z(float *mat, float angle) nuclear@3: { nuclear@3: set_identity(mat); nuclear@3: nuclear@3: mat[0] = cos(angle); nuclear@3: mat[1] = -sin(angle); nuclear@3: mat[4] = sin(angle); nuclear@3: mat[5] = cos(angle); nuclear@3: } nuclear@3: nuclear@3: static void set_ortho(float *mat, float aspect) nuclear@3: { nuclear@3: set_identity(mat); nuclear@3: mat[0] = 1.0 / aspect; nuclear@3: } nuclear@3: nuclear@3: static void display() nuclear@3: { nuclear@3: unsigned int msec = timeGetTime(); nuclear@3: nuclear@3: float fbcolor[] = {0.2f, 0.2f, 0.2f, 1.0f}; nuclear@3: ctx->ClearRenderTargetView(rtarg_view, fbcolor); nuclear@3: nuclear@3: // set render state constant buffer data nuclear@3: set_ortho(rstate.projection, (float)width / (float)height); nuclear@3: set_rotation_z(rstate.modelview, msec / 1000.0); nuclear@3: nuclear@3: ctx->UpdateSubresource(rstate_buf, 0, 0, &rstate, 0, 0); nuclear@3: ctx->VSSetConstantBuffers(0, 1, &rstate_buf); nuclear@3: nuclear@3: nuclear@3: unsigned int stride = sizeof(Vertex); nuclear@3: unsigned int offset = 0; nuclear@3: ctx->IASetVertexBuffers(0, 1, &vbuf, &stride, &offset); nuclear@3: ctx->IASetPrimitiveTopology(D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST); nuclear@3: ctx->IASetInputLayout(vertex_layout); nuclear@3: nuclear@3: ctx->VSSetShader(vsdr, 0, 0); nuclear@3: ctx->PSSetShader(psdr, 0, 0); nuclear@3: nuclear@3: ctx->Draw(3, 0); nuclear@3: nuclear@3: swap->Present(0, 0); nuclear@3: } nuclear@3: nuclear@3: static void reshape(int x, int y) nuclear@3: { nuclear@3: width = x; nuclear@3: height = y; nuclear@3: nuclear@3: D3D11_VIEWPORT vp; nuclear@3: vp.Width = (float)x; nuclear@3: vp.Height = (float)y; nuclear@3: vp.MinDepth = 0; nuclear@3: vp.MaxDepth = 1; nuclear@3: vp.TopLeftX = 0; nuclear@3: vp.TopLeftY = 0; nuclear@3: ctx->RSSetViewports(1, &vp); nuclear@3: nuclear@3: // TODO probably we also need to resize render targets or whatever... nuclear@3: } nuclear@3: nuclear@3: static void keyb(int key, bool pressed) nuclear@3: { nuclear@3: if(key == 27) { nuclear@3: exit(0); nuclear@3: } nuclear@3: } nuclear@3: nuclear@3: // ---- system crap ---- nuclear@3: nuclear@3: static HWND create_window(int xsz, int ysz) nuclear@3: { nuclear@3: HINSTANCE app_inst = GetModuleHandle(0); nuclear@3: nuclear@3: WNDCLASS wclass; nuclear@3: memset(&wclass, 0, sizeof wclass); nuclear@3: wclass.hInstance = app_inst; nuclear@3: wclass.lpfnWndProc = win_proc; nuclear@3: wclass.lpszClassName = "mutantstargoatwin"; nuclear@3: wclass.style = CS_HREDRAW | CS_VREDRAW | CS_OWNDC; nuclear@3: wclass.hIcon = LoadIcon(0, IDI_APPLICATION); nuclear@3: wclass.hCursor = LoadCursor(0, IDC_ARROW); nuclear@3: wclass.hbrBackground = (HBRUSH)GetStockObject(BLACK_BRUSH); nuclear@3: RegisterClass(&wclass); nuclear@3: nuclear@3: int posx = (GetSystemMetrics(SM_CXSCREEN) - xsz) / 2; nuclear@3: int posy = (GetSystemMetrics(SM_CYSCREEN) - ysz) / 2; nuclear@3: nuclear@3: HWND win = CreateWindow("mutantstargoatwin", "DX11 Test", WS_OVERLAPPEDWINDOW, posx, posy, nuclear@3: xsz, ysz, 0, 0, app_inst, 0); nuclear@3: ShowWindow(win, SW_SHOW); nuclear@3: nuclear@3: // initialize D3D device nuclear@3: DXGI_SWAP_CHAIN_DESC swap_desc; nuclear@3: memset(&swap_desc, 0, sizeof swap_desc); nuclear@3: swap_desc.BufferCount = 1; nuclear@3: swap_desc.BufferDesc.Width = xsz; nuclear@3: swap_desc.BufferDesc.Height = ysz; nuclear@3: swap_desc.BufferDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM; nuclear@3: swap_desc.BufferDesc.RefreshRate.Numerator = 60; nuclear@3: swap_desc.BufferDesc.RefreshRate.Denominator = 1; nuclear@3: swap_desc.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT; nuclear@3: swap_desc.OutputWindow = win; nuclear@3: swap_desc.SampleDesc.Count = 1; nuclear@3: swap_desc.SampleDesc.Quality = 0; nuclear@3: swap_desc.Windowed = 1; nuclear@3: nuclear@3: D3D_FEATURE_LEVEL feature_level = D3D_FEATURE_LEVEL_11_0; nuclear@3: nuclear@3: if(D3D11CreateDeviceAndSwapChain(0, D3D_DRIVER_TYPE_HARDWARE, 0, 0, &feature_level, 1, nuclear@3: D3D11_SDK_VERSION, &swap_desc, &swap, &dev, 0, &ctx) != 0) { nuclear@3: fprintf(stderr, "Failed to create d3d device and swap chain\n"); nuclear@3: return 0; nuclear@3: } nuclear@3: nuclear@3: ID3D11Texture2D *rtex; nuclear@3: if(swap->GetBuffer(0, __uuidof(ID3D11Texture2D), (void**)&rtex) != 0) { nuclear@3: fprintf(stderr, "Failed to get default render target texture\n"); nuclear@3: return 0; nuclear@3: } nuclear@3: if(dev->CreateRenderTargetView(rtex, 0, &rtarg_view) != 0) { nuclear@3: fprintf(stderr, "Failed to create render target view\n"); nuclear@3: rtex->Release(); nuclear@3: return 0; nuclear@3: } nuclear@3: rtex->Release(); nuclear@3: ctx->OMSetRenderTargets(1, &rtarg_view, 0); nuclear@3: nuclear@3: reshape(xsz, ysz); nuclear@3: return win; nuclear@3: } nuclear@3: nuclear@3: static void destroy_window(HWND win) nuclear@3: { nuclear@3: CloseWindow(win); nuclear@3: UnregisterClass("mutantstargoatwin", GetModuleHandle(0)); nuclear@3: nuclear@3: rtarg_view->Release(); nuclear@3: ctx->Release(); nuclear@3: dev->Release(); nuclear@3: swap->Release(); nuclear@3: } nuclear@3: nuclear@3: static void main_loop() nuclear@3: { nuclear@3: MSG msg; nuclear@3: nuclear@3: for(;;) { nuclear@3: while(PeekMessage(&msg, win, 0, 0, PM_REMOVE)) { nuclear@3: TranslateMessage(&msg); nuclear@3: DispatchMessage(&msg); nuclear@3: nuclear@3: if(msg.message == WM_QUIT) { nuclear@3: return; nuclear@3: } nuclear@3: } nuclear@3: nuclear@3: display(); nuclear@3: } nuclear@3: } nuclear@3: nuclear@3: static long CALLBACK win_proc(HWND win, unsigned int msg, unsigned int wparam, long lparam) nuclear@3: { nuclear@3: switch(msg) { nuclear@3: case WM_KEYDOWN: nuclear@3: keyb(wparam, true); nuclear@3: break; nuclear@3: nuclear@3: case WM_KEYUP: nuclear@3: keyb(wparam, false); nuclear@3: break; nuclear@3: nuclear@3: default: nuclear@3: return DefWindowProc(win, msg, wparam, lparam); nuclear@3: } nuclear@3: return 0; nuclear@3: }