Files
lity3d/Demo/game_test.c
T

223 lines
9.9 KiB
C

#include <windows.h>
#include <d3d11.h>
#include <d3dcompiler.h>
#include <math.h>
#include <stdint.h>
#include <string.h>
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;
}