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