Movatterモバイル変換


[0]ホーム

URL:


Skip to content
Search Gists
Sign in Sign up

Instantly share code, notes, and snippets.

@d7samurai
Last activeAugust 17, 2025 16:07
    • Star(10)You must be signed in to star a gist
    • Fork(0)You must be signed in to fork a gist

    Select an option

    Save d7samurai/a8dc490c54a714f8385f512d95278e0b to your computer and use it in GitHub Desktop.
    Minimal D3D11 bonus material: simple 2D rendering

    image

    Plain 2D rendering in D3D11, without the distracting feature set of acomplete sprite renderer and allowingarbitrarily placed triangle vertices with absolute pixel coordinate positioning (there's reallyno need for the sometimes confusing complication of a full-on projection matrix pipeline for UI and 2D games). Like theoriginal Minimal D3D11, this one uses a canonical 1:1TRIANGLELIST vertex buffer with input layout, so no fancy manual custom buffer fetching and in-shader instanced quad expansion here. As usual: complete, runnable single-function app. ~160 LOC. No modern C++, OOP or (other) obscuring cruft.

    Still not plain enough? Here's aneven simpler variant (no texturing or alpha blending).

    As with all of these demos, remember to keepgpu.hlsl in theworkingdirectory of the executable.

    #pragma comment(lib, "user32")
    #pragma comment(lib, "d3d11")
    #pragma comment(lib, "d3dcompiler")
    ///////////////////////////////////////////////////////////////////////////////////////////////////
    #include<windows.h>
    #include<d3d11.h>
    #include<d3dcompiler.h>
    ///////////////////////////////////////////////////////////////////////////////////////////////////
    #defineTEXTURE_WIDTH17
    #defineTEXTURE_HEIGHT25
    unsignedlonglong texturedata[] =// skull texture. 17 x 25 pixels, 8 bits per pixel (grayscale) for compactness
    {
    0x0000000000000000,0x0000000000000000,0xdd00000000000000,0x00000000b2e0dede,0xe1dc000000000000,0x00afaeaeaec8c8c8,
    0xc7e3000000000000,0x89b09999c3ddddc3,0xc7dd0000000000ae,0x9b99afb0c6dbddc6,0xc400000000af899b,0xb0aeaec6c6dedcc6,
    0xdd0000008a9c99af,0xadadaec4dedcdcc4,0x0000599b9aaeafaf,0xadadc6c6ddddc6c6,0x005c9a9aafafadae,0xadacc6c3e0ddc600,
    0x5c9d5ab0b0aeadad,0xaddedcdcc6ae0000,0x9f5ac4c4c7c6adad,0x895e89ae5d00005c,0x5b56578dc6aeaeb0,0x18185c3300005a5a,
    0x1818198cae8c1716,0x195a330000305b31,0x171617af5a331718,0x8ec60000315a5b30,0x165b8b8a58321718,0xe000005b8c5a3132,
    0x8a17dd8d5c188db1,0x000089ad8a5a1658,0x3219da888eaf8b5b,0x00323034898b8d5b,0x16aeae1719590000,0x00301717af8d3089,
    0xad5a32dc00000000,0x005a1959ad8c8bb0,0x8d198a0000000000,0x58318b17e217dc5a,0x8a8a000000000000,0x5b3230185a5b2f18,
    0xae00000000000033,0xb02fdc30de18ddaf,0x000000000000335a,0xb0e1aeb1afafae00,0x0000000000005daf,0xadafb1afb0000000,
    0x0000000000005b5c,0x898b8b0000000000,0x0000000000005a5c,0x0000000000000000,0x0000000000000000,0x0000000000000000,
    };
    ///////////////////////////////////////////////////////////////////////////////////////////////////
    int WINAPIWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine,int nShowCmd)
    {
    WNDCLASSA wndclass = {0, DefWindowProcA,0,0,0,0,0,0,0,"d7" };
    RegisterClassA(&wndclass);
    HWND window =CreateWindowExA(0,"d7",0,0x91000000,0,0,0,0,0,0,0,0);
    ///////////////////////////////////////////////////////////////////////////////////////////////
    D3D_FEATURE_LEVEL featurelevels[] = { D3D_FEATURE_LEVEL_11_0 };
    DXGI_SWAP_CHAIN_DESC swapchaindesc = {};
    swapchaindesc.BufferDesc.Format = DXGI_FORMAT_B8G8R8A8_UNORM;// non-srgb for simplicity here. see other minimal gists for srgb setup
    swapchaindesc.SampleDesc.Count =1;
    swapchaindesc.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT;
    swapchaindesc.BufferCount =2;
    swapchaindesc.OutputWindow = window;
    swapchaindesc.Windowed =TRUE;
    swapchaindesc.SwapEffect = DXGI_SWAP_EFFECT_FLIP_DISCARD;
    IDXGISwapChain* swapchain;
    ID3D11Device* device;
    ID3D11DeviceContext* devicecontext;
    D3D11CreateDeviceAndSwapChain(nullptr, D3D_DRIVER_TYPE_HARDWARE,nullptr, D3D11_CREATE_DEVICE_BGRA_SUPPORT, featurelevels,ARRAYSIZE(featurelevels), D3D11_SDK_VERSION, &swapchaindesc, &swapchain, &device,nullptr, &devicecontext);
    swapchain->GetDesc(&swapchaindesc);// get actual dimensions
    ///////////////////////////////////////////////////////////////////////////////////////////////
    ID3D11Texture2D* framebuffer;
    swapchain->GetBuffer(0,__uuidof(ID3D11Texture2D), (void**)&framebuffer);// get the swapchain's buffer
    ID3D11RenderTargetView* framebufferRTV;
    device->CreateRenderTargetView(framebuffer,nullptr, &framebufferRTV);// and make it a render target [view]
    ///////////////////////////////////////////////////////////////////////////////////////////////
    ID3DBlob* vertexshaderCSO;
    D3DCompileFromFile(L"gpu.hlsl",0,0,"VsMain","vs_5_0",0,0, &vertexshaderCSO,0);
    ID3D11VertexShader* vertexshader;
    device->CreateVertexShader(vertexshaderCSO->GetBufferPointer(), vertexshaderCSO->GetBufferSize(),0, &vertexshader);
    D3D11_INPUT_ELEMENT_DESC inputelementdesc[] =// maps to vertexdesc struct in gpu.hlsl via semantic names ("POS", "TEX", "COL")
    {
    {"POS",0, DXGI_FORMAT_R32G32_FLOAT,0,0, D3D11_INPUT_PER_VERTEX_DATA,0 },// float2 position (x, y)
    {"TEX",0, DXGI_FORMAT_R32G32_FLOAT,0, D3D11_APPEND_ALIGNED_ELEMENT, D3D11_INPUT_PER_VERTEX_DATA,0 },// float2 texcoord (u, v)
    {"COL",0, DXGI_FORMAT_R32G32B32A32_FLOAT,0, D3D11_APPEND_ALIGNED_ELEMENT, D3D11_INPUT_PER_VERTEX_DATA,0 },// float4 color (r, g, b, a)
    };
    ID3D11InputLayout* inputlayout;
    device->CreateInputLayout(inputelementdesc,ARRAYSIZE(inputelementdesc), vertexshaderCSO->GetBufferPointer(), vertexshaderCSO->GetBufferSize(), &inputlayout);
    ///////////////////////////////////////////////////////////////////////////////////////////////
    ID3DBlob* pixelshaderCSO;
    D3DCompileFromFile(L"gpu.hlsl",0,0,"PsMain","ps_5_0",0,0, &pixelshaderCSO,0);
    ID3D11PixelShader* pixelshader;
    device->CreatePixelShader(pixelshaderCSO->GetBufferPointer(), pixelshaderCSO->GetBufferSize(),0, &pixelshader);
    ///////////////////////////////////////////////////////////////////////////////////////////////
    D3D11_RASTERIZER_DESC rasterizerdesc = { D3D11_FILL_SOLID, D3D11_CULL_NONE };
    ID3D11RasterizerState* rasterizerstate;
    device->CreateRasterizerState(&rasterizerdesc, &rasterizerstate);
    ///////////////////////////////////////////////////////////////////////////////////////////////
    D3D11_SAMPLER_DESC samplerdesc = { D3D11_FILTER_MIN_MAG_MIP_POINT, D3D11_TEXTURE_ADDRESS_WRAP, D3D11_TEXTURE_ADDRESS_WRAP, D3D11_TEXTURE_ADDRESS_WRAP };
    ID3D11SamplerState* samplerstate;
    device->CreateSamplerState(&samplerdesc, &samplerstate);
    ///////////////////////////////////////////////////////////////////////////////////////////////
    D3D11_BLEND_DESC blenddesc = {FALSE,FALSE, {TRUE, D3D11_BLEND_SRC_ALPHA , D3D11_BLEND_INV_SRC_ALPHA, D3D11_BLEND_OP_ADD, D3D11_BLEND_ZERO, D3D11_BLEND_ZERO, D3D11_BLEND_OP_ADD, D3D11_COLOR_WRITE_ENABLE_ALL } };
    ID3D11BlendState* blendstate;
    device->CreateBlendState(&blenddesc, &blendstate);
    ///////////////////////////////////////////////////////////////////////////////////////////////
    float constants[2] = {2.0f / swapchaindesc.BufferDesc.Width, -2.0f / swapchaindesc.BufferDesc.Height };// precalc for simple screen coordinate transform in shader (instead of full-on projection matrix)
    D3D11_BUFFER_DESC constantbufferdesc = {};
    constantbufferdesc.ByteWidth =sizeof(constants) +0xf &0xfffffff0;
    constantbufferdesc.Usage = D3D11_USAGE_IMMUTABLE;
    constantbufferdesc.BindFlags = D3D11_BIND_CONSTANT_BUFFER;
    D3D11_SUBRESOURCE_DATA constantbufferSRD = { constants };
    ID3D11Buffer* constantbuffer;
    device->CreateBuffer(&constantbufferdesc, &constantbufferSRD, &constantbuffer);
    ///////////////////////////////////////////////////////////////////////////////////////////////
    D3D11_TEXTURE2D_DESC texturedesc = {};
    texturedesc.Width = TEXTURE_WIDTH;
    texturedesc.Height = TEXTURE_HEIGHT;
    texturedesc.MipLevels =1;
    texturedesc.ArraySize =1;
    texturedesc.Format = DXGI_FORMAT_R8_UNORM;// 8 bits per pixel
    texturedesc.SampleDesc.Count =1;
    texturedesc.Usage = D3D11_USAGE_IMMUTABLE;
    texturedesc.BindFlags = D3D11_BIND_SHADER_RESOURCE;
    D3D11_SUBRESOURCE_DATA textureSRD = {};
    textureSRD.pSysMem = texturedata;
    textureSRD.SysMemPitch = TEXTURE_WIDTH *1;// 1 byte per pixel (R8)
    ID3D11Texture2D* texture;
    device->CreateTexture2D(&texturedesc, &textureSRD, &texture);
    ID3D11ShaderResourceView* textureSRV;
    device->CreateShaderResourceView(texture,nullptr, &textureSRV);
    ///////////////////////////////////////////////////////////////////////////////////////////////
    #defineMAX_VERTICES1024// arbitrary limit
    structvertexdesc {float x, y, u, v, r, g, b, a; };// float2 position, float2 texcoord, float4 color
    ///////////////////////////////////////////////////////////////////////////////////////////////
    D3D11_BUFFER_DESC vertexbufferdesc = {};
    vertexbufferdesc.ByteWidth =sizeof(vertexdesc) * MAX_VERTICES;
    vertexbufferdesc.Usage = D3D11_USAGE_DYNAMIC;// updated every frame
    vertexbufferdesc.CPUAccessFlags = D3D11_CPU_ACCESS_WRITE;
    vertexbufferdesc.BindFlags = D3D11_BIND_VERTEX_BUFFER;
    ID3D11Buffer* vertexbuffer;
    device->CreateBuffer(&vertexbufferdesc,nullptr, &vertexbuffer);
    ///////////////////////////////////////////////////////////////////////////////////////////////
    FLOAT clearcolor[4] = {0.1725f,0.1725f,0.1725f,1.0f };// RGBA
    D3D11_VIEWPORT viewport = {0,0, (float)swapchaindesc.BufferDesc.Width, (float)swapchaindesc.BufferDesc.Height,0,1 };
    UINT stride =sizeof(vertexdesc);
    UINT offset =0;
    ///////////////////////////////////////////////////////////////////////////////////////////////
    vertexdesc* vertexbatch = (vertexdesc*)HeapAlloc(GetProcessHeap(),0,sizeof(vertexdesc) * MAX_VERTICES);// per frame vertex batch (cpu-local buffer)
    ///////////////////////////////////////////////////////////////////////////////////////////////
    while (true)
    {
    MSG msg;
    while (PeekMessageA(&msg,nullptr,0,0, PM_REMOVE))
    {
    if (msg.message == WM_KEYDOWN)return0;// PRESS ANY KEY TO EXIT
    DispatchMessageA(&msg);
    }
    ///////////////////////////////////////////////////////////////////////////////////////////
    int vertexcount =0;// start a new vertex batch every frame
    // triangle 1:
    {
    // vertex 1
    vertexdesc vertex;
    vertex.x =100;// screen coordinates in pixels (xy)
    vertex.y =100;
    vertex.u =0.0f;// texture coordinates (uv)
    vertex.v =0.0f;
    vertex.r =1.0f;// color (rgba)
    vertex.g =1.0f;
    vertex.b =1.0f;
    vertex.a =1.0f;
    vertexbatch[vertexcount++] = vertex;// add vertex to batch
    // vertex 2
    vertexbatch[vertexcount++] = {252,300,1.0f,1.0f,1.0f,1.0f,1.0f,1.0f };// x, y, u, v, r, g, b, a
    // vertex 3
    vertexbatch[vertexcount++] = {100,300,0.0f,1.0f,1.0f,1.0f,1.0f,1.0f };
    }
    // triangle 2:
    vertexbatch[vertexcount++] = {100,100,0.0f,0.0f,1.0f,1.0f,1.0f,1.0f };
    vertexbatch[vertexcount++] = {252,100,1.0f,0.0f,1.0f,1.0f,1.0f,1.0f };
    vertexbatch[vertexcount++] = {252,300,1.0f,1.0f,1.0f,1.0f,1.0f,1.0f };
    // triangle 3:
    vertexbatch[vertexcount++] = {296,104,0.0f,0.0f,0.803f,0.000f,0.290f,1.0f };
    vertexbatch[vertexcount++] = {448,304,1.0f,1.0f,0.952f,0.439f,0.105f,1.0f };
    vertexbatch[vertexcount++] = {296,304,0.0f,1.0f,0.988f,0.721f,0.023f,1.0f };
    // triangle 4:
    vertexbatch[vertexcount++] = {304,96,0.0f,0.0f,0.011f,0.698f,0.286f,1.0f };
    vertexbatch[vertexcount++] = {456,96,1.0f,0.0f,0.000f,0.541f,0.819f,1.0f };
    vertexbatch[vertexcount++] = {456,296,1.0f,1.0f,0.392f,0.376f,0.670f,1.0f };
    ///////////////////////////////////////////////////////////////////////////////////////////
    D3D11_MAPPED_SUBRESOURCE vertexbufferMSR;
    devicecontext->Map(vertexbuffer,0, D3D11_MAP_WRITE_DISCARD,0, &vertexbufferMSR);
    {
    memcpy(vertexbufferMSR.pData, vertexbatch,sizeof(vertexdesc) * vertexcount);// send vertex batch to gpu
    }
    devicecontext->Unmap(vertexbuffer,0);
    ///////////////////////////////////////////////////////////////////////////////////////////
    devicecontext->ClearRenderTargetView(framebufferRTV, clearcolor);
    devicecontext->IASetPrimitiveTopology(D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST);// 3 vertices per triangle
    devicecontext->IASetInputLayout(inputlayout);
    devicecontext->IASetVertexBuffers(0,1, &vertexbuffer, &stride, &offset);
    devicecontext->VSSetShader(vertexshader,nullptr,0);
    devicecontext->VSSetConstantBuffers(0,1, &constantbuffer);
    devicecontext->RSSetViewports(1, &viewport);
    devicecontext->RSSetState(rasterizerstate);
    devicecontext->PSSetShader(pixelshader,nullptr,0);
    devicecontext->PSSetShaderResources(0,1, &textureSRV);
    devicecontext->PSSetSamplers(0,1, &samplerstate);
    devicecontext->OMSetRenderTargets(1, &framebufferRTV,nullptr);
    devicecontext->OMSetBlendState(blendstate,nullptr,0xffffffff);
    ///////////////////////////////////////////////////////////////////////////////////////////
    devicecontext->Draw(vertexcount,0);
    ///////////////////////////////////////////////////////////////////////////////////////////
    swapchain->Present(1,0);
    }
    }
    cbuffer constants :register(b0)
    {
    float2 rn_screensize;// 2 / width, -2 / height
    }
    struct vertexdesc
    {
    float2 position : POS;
    float2 texcoord : TEX;
    float4 color : COL;
    };
    struct pixeldesc
    {
    float4 position :SV_POSITION;
    float2 texcoord : TEX;
    float4 color : COL;
    };
    Texture2D mytexture :register(t0);
    SamplerState mysampler :register(s0);
    pixeldescVsMain(vertexdesc vertex)
    {
    pixeldesc output;
    output.position =float4(vertex.position * rn_screensize -float2(1, -1),0,1);
    output.texcoord = vertex.texcoord;
    output.color = vertex.color;
    return output;
    }
    float4PsMain(pixeldesc pixel) :SV_TARGET
    {
    returnfloat4(mytexture.Sample(mysampler, pixel.texcoord).rrr * pixel.color.rgb, pixel.color.a);// .rrr because texture is red channel only (DXGI_FORMAT_R8_UNORM)
    }
    Sign up for freeto join this conversation on GitHub. Already have an account?Sign in to comment

    [8]ページ先頭

    ©2009-2025 Movatter.jp