#include #include #include #include #include #include typedef struct { float p[3], n[3], u[2], c[4]; } V3D; static ID3D11Device* g_dev = NULL; static ID3D11DeviceContext* g_ctx = NULL; static IDXGISwapChain* g_sc = NULL; static ID3D11RenderTargetView* g_rtv = NULL; static ID3D11VertexShader* g_vs = NULL; static ID3D11PixelShader* g_ps = NULL; static ID3D11InputLayout* g_il = NULL; static ID3D11Buffer* g_cb = NULL; static float cam_x = 0, cam_z = 0; static int key_w = 0, key_s = 0, key_a = 0, key_d = 0; static int key_left = 0, key_right = 0; static int sel = 0; static void Init(HWND h) { HRESULT hr; DXGI_SWAP_CHAIN_DESC sd; memset(&sd, 0, sizeof(sd)); sd.BufferCount = 2; sd.BufferDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM; sd.BufferDesc.RefreshRate.Numerator = 60; sd.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT; sd.OutputWindow = h; sd.SampleDesc.Count = 1; sd.Windowed = TRUE; sd.SwapEffect = DXGI_SWAP_EFFECT_DISCARD; D3D_FEATURE_LEVEL fl = D3D_FEATURE_LEVEL_11_0; D3D_FEATURE_LEVEL got; hr = D3D11CreateDeviceAndSwapChain(NULL, D3D_DRIVER_TYPE_HARDWARE, NULL, 0, &fl, 1, D3D11_SDK_VERSION, &sd, &g_sc, &g_dev, &got, &g_ctx); if (FAILED(hr)) { return; } ID3D11Texture2D* bb = NULL; hr = g_sc->lpVtbl->GetBuffer(g_sc, 0, &IID_ID3D11Texture2D, (void**)&bb); if (FAILED(hr) || !bb) { return; } hr = g_dev->lpVtbl->CreateRenderTargetView(g_dev, (ID3D11Resource*)bb, NULL, &g_rtv); bb->lpVtbl->Release(bb); if (FAILED(hr)) { return; } const char* vs_src = "cbuffer CB:register(b0){float4x4 WVP;};" "struct I{float3 p:POSITION;float3 n:NORMAL;float2 u:TEXCOORD;float4 c:COLOR;};" "struct O{float4 p:SV_POSITION;float4 c:COLOR;};" "O main(I i){O o;o.p=mul(float4(i.p,1),WVP);o.c=i.c;return o;}"; const char* ps_src = "float4 main(float4 pos:SV_POSITION, float4 col:COLOR):SV_Target{return col;}"; ID3DBlob *b1 = NULL, *b2 = NULL, *e1 = NULL, *e2 = NULL; D3DCompile(vs_src, (UINT)strlen(vs_src), NULL, NULL, NULL, "main", "vs_5_0", 0, 0, &b1, &e1); if (e1) { e1->lpVtbl->Release(e1); e1 = NULL; } D3DCompile(ps_src, (UINT)strlen(ps_src), NULL, NULL, NULL, "main", "ps_5_0", 0, 0, &b2, &e2); if (e2) { e2->lpVtbl->Release(e2); e2 = NULL; } if (!b1 || !b2) { return; } g_dev->lpVtbl->CreateVertexShader(g_dev, b1->lpVtbl->GetBufferPointer(b1), b1->lpVtbl->GetBufferSize(b1), NULL, &g_vs); g_dev->lpVtbl->CreatePixelShader(g_dev, b2->lpVtbl->GetBufferPointer(b2), b2->lpVtbl->GetBufferSize(b2), NULL, &g_ps); D3D11_INPUT_ELEMENT_DESC el[4]; memset(el, 0, sizeof(el)); el[0].SemanticName = "POSITION"; el[0].Format = DXGI_FORMAT_R32G32B32_FLOAT; el[0].InputSlotClass = D3D11_INPUT_PER_VERTEX_DATA; el[1].SemanticName = "NORMAL"; el[1].AlignedByteOffset = 12; el[1].Format = DXGI_FORMAT_R32G32B32_FLOAT; el[1].InputSlotClass = D3D11_INPUT_PER_VERTEX_DATA; el[2].SemanticName = "TEXCOORD"; el[2].AlignedByteOffset = 24; el[2].Format = DXGI_FORMAT_R32G32_FLOAT; el[2].InputSlotClass = D3D11_INPUT_PER_VERTEX_DATA; el[3].SemanticName = "COLOR"; el[3].AlignedByteOffset = 32; el[3].Format = DXGI_FORMAT_R32G32B32A32_FLOAT; el[3].InputSlotClass = D3D11_INPUT_PER_VERTEX_DATA; g_dev->lpVtbl->CreateInputLayout(g_dev, el, 4, b1->lpVtbl->GetBufferPointer(b1), b1->lpVtbl->GetBufferSize(b1), &g_il); b1->lpVtbl->Release(b1); b2->lpVtbl->Release(b2); D3D11_BUFFER_DESC cbd; memset(&cbd, 0, sizeof(cbd)); cbd.ByteWidth = 256; cbd.Usage = D3D11_USAGE_DEFAULT; cbd.BindFlags = D3D11_BIND_CONSTANT_BUFFER; g_dev->lpVtbl->CreateBuffer(g_dev, &cbd, NULL, &g_cb); } static void DrawCube(float cx, float cy, float cz, float s, float cr, float cg, float cb2) { V3D v[24]; float f[6][4][3] = { {{-1,-1,-1},{1,-1,-1},{1,1,-1},{-1,1,-1}}, {{1,-1,-1},{1,-1,1},{1,1,1},{1,1,-1}}, {{1,-1,1},{-1,-1,1},{-1,1,1},{1,1,1}}, {{-1,-1,1},{-1,-1,-1},{-1,1,-1},{-1,1,1}}, {{-1,1,-1},{1,1,-1},{1,1,1},{-1,1,1}}, {{-1,-1,1},{1,-1,1},{1,-1,-1},{-1,-1,-1}} }; float nm[6][3] = {{0,0,-1},{1,0,0},{0,0,1},{-1,0,0},{0,1,0},{0,-1,0}}; for (int fi = 0; fi < 6; fi++) for (int vi = 0; vi < 4; vi++) { int i = fi * 4 + vi; v[i].p[0] = f[fi][vi][0] * s + cx; v[i].p[1] = f[fi][vi][1] * s + cy; v[i].p[2] = f[fi][vi][2] * s + cz; v[i].n[0] = nm[fi][0]; v[i].n[1] = nm[fi][1]; v[i].n[2] = nm[fi][2]; v[i].c[0] = cr; v[i].c[1] = cg; v[i].c[2] = cb2; v[i].c[3] = 1; } uint32_t ix[36]; for (int fi = 0; fi < 6; fi++) { int b = fi * 4; ix[fi*6]=b; ix[fi*6+1]=b+1; ix[fi*6+2]=b+2; ix[fi*6+3]=b; ix[fi*6+4]=b+2; ix[fi*6+5]=b+3; } ID3D11Buffer *vb = NULL, *ib = NULL; D3D11_BUFFER_DESC bd; D3D11_SUBRESOURCE_DATA sd; memset(&bd, 0, sizeof(bd)); memset(&sd, 0, sizeof(sd)); bd.ByteWidth = sizeof(V3D) * 24; bd.Usage = D3D11_USAGE_DEFAULT; bd.BindFlags = D3D11_BIND_VERTEX_BUFFER; sd.pSysMem = v; g_dev->lpVtbl->CreateBuffer(g_dev, &bd, &sd, &vb); bd.ByteWidth = sizeof(uint32_t) * 36; bd.BindFlags = D3D11_BIND_INDEX_BUFFER; sd.pSysMem = ix; g_dev->lpVtbl->CreateBuffer(g_dev, &bd, &sd, &ib); UINT s2 = sizeof(V3D), o = 0; g_ctx->lpVtbl->IASetVertexBuffers(g_ctx, 0, 1, &vb, &s2, &o); g_ctx->lpVtbl->IASetIndexBuffer(g_ctx, ib, DXGI_FORMAT_R32_UINT, 0); g_ctx->lpVtbl->DrawIndexed(g_ctx, 36, 0, 0); ib->lpVtbl->Release(ib); vb->lpVtbl->Release(vb); } static void Frame(void) { float dt = 0.016f, spd = 3.0f * dt; if (key_w) cam_z += spd; if (key_s) cam_z -= spd; if (key_a) cam_x -= spd; if (key_d) cam_x += spd; if (key_left) sel = (sel + 3) % 4; if (key_right) sel = (sel + 1) % 4; float fov = 1.0f / tanf(0.4f), asp = 1280.0f / 720.0f; float mvp[16]; memset(mvp, 0, sizeof(mvp)); mvp[0] = fov / asp; mvp[5] = -fov; mvp[10] = 1; mvp[11] = -1; mvp[14] = 0.1f; mvp[15] = 1; float m2[16]; memcpy(m2, mvp, 64); for (int i = 0; i < 4; i++) for (int j = 0; j < 4; j++) { float t = m2[i*4+j]; m2[i*4+j] = m2[j*4+i]; m2[j*4+i] = t; } float cl[4] = {.15f, .18f, .25f, 1}; g_ctx->lpVtbl->OMSetRenderTargets(g_ctx, 1, &g_rtv, NULL); g_ctx->lpVtbl->ClearRenderTargetView(g_ctx, g_rtv, cl); D3D11_VIEWPORT vp; memset(&vp, 0, sizeof(vp)); vp.Width = 1280; vp.Height = 720; vp.MaxDepth = 1; g_ctx->lpVtbl->RSSetViewports(g_ctx, 1, &vp); D3D11_RASTERIZER_DESC rd; memset(&rd, 0, sizeof(rd)); rd.FillMode = D3D11_FILL_SOLID; rd.CullMode = D3D11_CULL_NONE; ID3D11RasterizerState* rs = NULL; g_dev->lpVtbl->CreateRasterizerState(g_dev, &rd, &rs); g_ctx->lpVtbl->RSSetState(g_ctx, rs); D3D11_DEPTH_STENCIL_DESC ds; memset(&ds, 0, sizeof(ds)); ds.DepthEnable = FALSE; ID3D11DepthStencilState* dss = NULL; g_dev->lpVtbl->CreateDepthStencilState(g_dev, &ds, &dss); g_ctx->lpVtbl->OMSetDepthStencilState(g_ctx, dss, 0); g_ctx->lpVtbl->IASetPrimitiveTopology(g_ctx, D3D_PRIMITIVE_TOPOLOGY_TRIANGLELIST); g_ctx->lpVtbl->VSSetShader(g_ctx, g_vs, NULL, 0); g_ctx->lpVtbl->PSSetShader(g_ctx, g_ps, NULL, 0); g_ctx->lpVtbl->IASetInputLayout(g_ctx, g_il); g_ctx->lpVtbl->VSSetConstantBuffers(g_ctx, 0, 1, &g_cb); g_ctx->lpVtbl->UpdateSubresource(g_ctx, (ID3D11Resource*)g_cb, 0, NULL, m2, 0, 0); float colors[4][3] = {{1,.3f,.3f},{.3f,1,.3f},{.3f,.3f,1},{.8f,.8f,.2f}}; float sizes[4] = {0.3f, 0.25f, 0.2f, 0.35f}; for (int i = 0; i < 4; i++) { float cr = colors[i][0], cg = colors[i][1], cb = colors[i][2]; if (i == sel) { cr = 1; cg = 1; cb = 1; } DrawCube(-0.8f + i * 0.6f - cam_x, 0, 1.5f - cam_z, sizes[i], cr, cg, cb); } if (rs) rs->lpVtbl->Release(rs); if (dss) dss->lpVtbl->Release(dss); g_sc->lpVtbl->Present(g_sc, 1, 0); } static LRESULT CALLBACK WP(HWND h, UINT m, WPARAM w, LPARAM l) { switch (m) { case WM_KEYDOWN: switch (w) { case 'W': key_w = 1; break; case 'S': key_s = 1; break; case 'A': key_a = 1; break; case 'D': key_d = 1; break; case VK_LEFT: key_left = 1; break; case VK_RIGHT: key_right = 1; break; case '1': sel = 0; break; case '2': sel = 1; break; case '3': sel = 2; break; case '4': sel = 3; break; case VK_ESCAPE: PostQuitMessage(0); break; } break; case WM_KEYUP: switch (w) { case 'W': key_w = 0; break; case 'S': key_s = 0; break; case 'A': key_a = 0; break; case 'D': key_d = 0; break; case VK_LEFT: key_left = 0; break; case VK_RIGHT: key_right = 0; break; } break; case WM_DESTROY: PostQuitMessage(0); return 0; } return DefWindowProcW(h, m, w, l); } int WINAPI WinMain(HINSTANCE hI, HINSTANCE hP, LPSTR nC, int nS) { (void)hP; (void)nC; (void)nS; WNDCLASSEXW wc; memset(&wc, 0, sizeof(wc)); wc.cbSize = sizeof(wc); wc.style = CS_CLASSDC; wc.lpfnWndProc = WP; wc.hInstance = hI; wc.lpszClassName = L"game_test_cls"; RegisterClassExW(&wc); HWND hwnd = CreateWindowW(L"game_test_cls", L"lity3d Game Test", WS_OVERLAPPEDWINDOW, 100, 100, 1280, 720, NULL, NULL, hI, NULL); if (!hwnd) { MessageBoxA(NULL, "CreateWindow failed", "Error", MB_OK); return -1; } ShowWindow(hwnd, SW_SHOW); UpdateWindow(hwnd); Init(hwnd); MSG msg; while (1) { while (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) { TranslateMessage(&msg); DispatchMessage(&msg); if (msg.message == WM_QUIT) goto done; } Frame(); } done: if (g_cb) g_cb->lpVtbl->Release(g_cb); if (g_il) g_il->lpVtbl->Release(g_il); if (g_vs) g_vs->lpVtbl->Release(g_vs); if (g_ps) g_ps->lpVtbl->Release(g_ps); if (g_rtv) g_rtv->lpVtbl->Release(g_rtv); if (g_sc) g_sc->lpVtbl->Release(g_sc); if (g_ctx) g_ctx->lpVtbl->Release(g_ctx); if (g_dev) g_dev->lpVtbl->Release(g_dev); return 0; }