mltg 0.22.1

Direct2D wrapper library
Documentation
use raw_window_handle::{HasRawWindowHandle, RawWindowHandle};
use windows::Win32::{
    Foundation::{HMODULE, HWND},
    Graphics::{Direct3D::Fxc::*, Direct3D::*, Direct3D11::*, Dxgi::Common::*, Dxgi::*},
};
use winit::{dpi::*, event::*, event_loop::*, window::*};

#[repr(C)]
struct Vertex {
    position: [f32; 3],
    tex: [f32; 2],
}

impl Vertex {
    const fn new(position: [f32; 3], tex: [f32; 2]) -> Self {
        Self { position, tex }
    }
}

fn main() -> anyhow::Result<()> {
    let event_loop = EventLoop::new();
    let window = WindowBuilder::new()
        .with_title("mltg to_d3d11_texture")
        .with_inner_size(LogicalSize::new(640, 480))
        .build(&event_loop)?;
    let (device, device_context) = unsafe {
        const FEATURE_LEVELS: [D3D_FEATURE_LEVEL; 1] = [D3D_FEATURE_LEVEL_11_0];
        let mut device = None;
        let mut device_context = None;
        D3D11CreateDevice(
            None,
            D3D_DRIVER_TYPE_HARDWARE,
            HMODULE::default(),
            D3D11_CREATE_DEVICE_BGRA_SUPPORT,
            Some(&FEATURE_LEVELS),
            D3D11_SDK_VERSION,
            Some(&mut device),
            None,
            Some(&mut device_context),
        )
        .map(|_| (device.unwrap(), device_context.unwrap()))?
    };
    let dxgi_factory = unsafe { CreateDXGIFactory1::<IDXGIFactory2>()? };
    let window_size = window.inner_size();
    let swap_chain = unsafe {
        let RawWindowHandle::Win32(handle) = window.raw_window_handle() else { panic!() };
        dxgi_factory.CreateSwapChainForHwnd(
            &device,
            HWND(handle.hwnd as _),
            &DXGI_SWAP_CHAIN_DESC1 {
                Width: window_size.width,
                Height: window_size.height,
                Format: DXGI_FORMAT_B8G8R8A8_UNORM,
                BufferCount: 2,
                BufferUsage: DXGI_USAGE_RENDER_TARGET_OUTPUT,
                SwapEffect: DXGI_SWAP_EFFECT_FLIP_DISCARD,
                Scaling: DXGI_SCALING_NONE,
                SampleDesc: DXGI_SAMPLE_DESC {
                    Count: 1,
                    Quality: 0,
                },
                ..Default::default()
            },
            None,
            None,
        )?
    };
    let rtv = unsafe {
        let buffer = swap_chain.GetBuffer::<ID3D11Texture2D>(0)?;
        let mut rtv = None;
        device.CreateRenderTargetView(&buffer, None, Some(&mut rtv))?;
        rtv.unwrap()
    };
    let vertex_buffer = unsafe {
        const VERTICES: [Vertex; 4] = [
            Vertex::new([-0.5, 0.5, 0.0], [0.0, 0.0]),
            Vertex::new([0.5, 0.5, 0.0], [1.0, 0.0]),
            Vertex::new([-0.5, -0.5, 0.0], [0.0, 1.0]),
            Vertex::new([0.5, -0.5, 0.0], [1.0, 1.0]),
        ];
        let mut buffer = None;
        device.CreateBuffer(
            &D3D11_BUFFER_DESC {
                ByteWidth: std::mem::size_of::<[Vertex; 4]>() as _,
                Usage: D3D11_USAGE_DEFAULT,
                BindFlags: D3D11_BIND_VERTEX_BUFFER.0 as u32,
                ..Default::default()
            },
            Some(&D3D11_SUBRESOURCE_DATA {
                pSysMem: VERTICES.as_ptr() as _,
                ..Default::default()
            }),
            Some(&mut buffer),
        )?;
        buffer.unwrap()
    };
    let index_buffer = unsafe {
        const INDICES: [u32; 6] = [0, 1, 2, 1, 3, 2];
        let mut buffer = None;
        device.CreateBuffer(
            &D3D11_BUFFER_DESC {
                ByteWidth: std::mem::size_of::<[u32; 6]>() as _,
                Usage: D3D11_USAGE_DEFAULT,
                BindFlags: D3D11_BIND_INDEX_BUFFER.0 as u32,
                ..Default::default()
            },
            Some(&D3D11_SUBRESOURCE_DATA {
                pSysMem: INDICES.as_ptr() as _,
                ..Default::default()
            }),
            Some(&mut buffer),
        )?;
        buffer.unwrap()
    };
    let (vs, ps, input_layout) = unsafe {
        let hlsl_file = include_bytes!("../resources/tex.hlsl");
        let mut vs_blob = None;
        let mut ps_blob = None;
        let vs_blob = D3DCompile(
            hlsl_file.as_ptr() as _,
            hlsl_file.len(),
            windows::core::s!("tex.hlsl"),
            None,
            None,
            windows::core::s!("vs_main"),
            windows::core::s!("vs_5_0"),
            0,
            0,
            &mut vs_blob,
            None,
        )
        .map(|_| vs_blob.unwrap())?;
        let ps_blob = D3DCompile(
            hlsl_file.as_ptr() as _,
            hlsl_file.len(),
            windows::core::s!("tex.hlsl"),
            None,
            None,
            windows::core::s!("ps_main"),
            windows::core::s!("ps_5_0"),
            0,
            0,
            &mut ps_blob,
            None,
        )
        .map(|_| ps_blob.unwrap())?;
        let vs_blob = std::slice::from_raw_parts(
            vs_blob.GetBufferPointer() as *const u8,
            vs_blob.GetBufferSize(),
        );
        let ps_blob = std::slice::from_raw_parts(
            ps_blob.GetBufferPointer() as *const u8,
            ps_blob.GetBufferSize(),
        );
        let vs = {
            let mut vs = None;
            device.CreateVertexShader(&vs_blob, None, Some(&mut vs))?;
            vs.unwrap()
        };
        let ps = {
            let mut ps = None;
            device.CreatePixelShader(&ps_blob, None, Some(&mut ps))?;
            ps.unwrap()
        };
        let descs = [
            D3D11_INPUT_ELEMENT_DESC {
                SemanticName: windows::core::s!("POSITION"),
                SemanticIndex: 0,
                Format: DXGI_FORMAT_R32G32B32_FLOAT,
                InputSlot: 0,
                AlignedByteOffset: 0,
                InputSlotClass: D3D11_INPUT_PER_VERTEX_DATA,
                InstanceDataStepRate: 0,
            },
            D3D11_INPUT_ELEMENT_DESC {
                SemanticName: windows::core::s!("TEXCOORD"),
                SemanticIndex: 0,
                Format: DXGI_FORMAT_R32G32_FLOAT,
                InputSlot: 0,
                AlignedByteOffset: D3D11_APPEND_ALIGNED_ELEMENT,
                InputSlotClass: D3D11_INPUT_PER_VERTEX_DATA,
                InstanceDataStepRate: 0,
            },
        ];
        let input_layout = {
            let mut input_layout = None;
            device.CreateInputLayout(&descs, vs_blob, Some(&mut input_layout))?;
            input_layout.unwrap()
        };
        (vs, ps, input_layout)
    };
    let tex = unsafe {
        let mut tex = None;
        device.CreateTexture2D(
            &D3D11_TEXTURE2D_DESC {
                Usage: D3D11_USAGE_DEFAULT,
                BindFlags: (D3D11_BIND_RENDER_TARGET.0 | D3D11_BIND_SHADER_RESOURCE.0) as u32,
                Width: window_size.width,
                Height: window_size.height,
                ArraySize: 1,
                MipLevels: 1,
                Format: DXGI_FORMAT_R8G8B8A8_UNORM,
                SampleDesc: DXGI_SAMPLE_DESC {
                    Count: 1,
                    Quality: 0,
                },
                ..Default::default()
            },
            None,
            Some(&mut tex),
        )?;
        tex.unwrap()
    };
    let tex_view = unsafe {
        let mut tex_view = None;
        device.CreateShaderResourceView(&tex, None, Some(&mut tex_view))?;
        tex_view.unwrap()
    };
    let sampler = unsafe {
        let mut sampler = None;
        device.CreateSamplerState(
            &D3D11_SAMPLER_DESC {
                Filter: D3D11_FILTER_MIN_MAG_MIP_LINEAR,
                AddressU: D3D11_TEXTURE_ADDRESS_CLAMP,
                AddressV: D3D11_TEXTURE_ADDRESS_CLAMP,
                AddressW: D3D11_TEXTURE_ADDRESS_CLAMP,
                MinLOD: f32::MIN,
                MaxLOD: f32::MAX,
                MaxAnisotropy: 1,
                ..Default::default()
            },
            Some(&mut sampler),
        )?;
        sampler.unwrap()
    };
    let blend = unsafe {
        let rt = D3D11_RENDER_TARGET_BLEND_DESC {
            BlendEnable: true.into(),
            SrcBlend: D3D11_BLEND_SRC_ALPHA,
            DestBlend: D3D11_BLEND_INV_SRC_ALPHA,
            BlendOp: D3D11_BLEND_OP_ADD,
            SrcBlendAlpha: D3D11_BLEND_ONE,
            DestBlendAlpha: D3D11_BLEND_ZERO,
            BlendOpAlpha: D3D11_BLEND_OP_ADD,
            RenderTargetWriteMask: D3D11_COLOR_WRITE_ENABLE_ALL.0 as _,
        };
        let mut blend = None;
        device.CreateBlendState(
            &D3D11_BLEND_DESC {
                RenderTarget: [rt; 8],
                ..Default::default()
            },
            Some(&mut blend),
        )?;
        blend.unwrap()
    };
    let context = mltg::Context::new(mltg::Direct3D11::new(&device)?)?;
    let factory = context.create_factory();
    let target = context.create_render_target(&tex)?;
    let image = factory.create_image_from_file("resources/ferris.png")?;
    event_loop.run(move |event, _, control_flow| {
        *control_flow = ControlFlow::Wait;
        match event {
            Event::RedrawRequested(_) => unsafe {
                let dc = &device_context;
                let window_size = window.inner_size();
                context
                    .draw(&target, |cmd| {
                        let desc = {
                            let mut desc = D3D11_TEXTURE2D_DESC::default();
                            tex.GetDesc(&mut desc);
                            desc
                        };
                        cmd.clear([0.0, 0.0, 0.0, 0.0]);
                        cmd.draw_image(
                            &image,
                            mltg::Rect::new((0.0, 0.0), (desc.Width as f32, desc.Height as f32)),
                            None,
                            mltg::Interpolation::HighQualityCubic,
                        );
                    })
                    .unwrap();
                dc.ClearRenderTargetView(&rtv, &[0.0, 0.0, 0.3, 0.0]);
                dc.IASetPrimitiveTopology(D3D_PRIMITIVE_TOPOLOGY_TRIANGLELIST);
                dc.IASetInputLayout(&input_layout);
                dc.IASetIndexBuffer(&index_buffer, DXGI_FORMAT_R32_UINT, 0);
                dc.IASetVertexBuffers(
                    0,
                    1,
                    Some([Some(vertex_buffer.clone())].as_mut_ptr()),
                    Some([std::mem::size_of::<Vertex>() as u32].as_ptr()),
                    Some([0].as_ptr()),
                );
                dc.OMSetRenderTargets(Some(&[Some(rtv.clone())]), None);
                dc.OMSetBlendState(&blend, None, u32::MAX);
                dc.VSSetShader(&vs, None);
                dc.PSSetShader(&ps, None);
                dc.PSSetShaderResources(0, Some(&[Some(tex_view.clone())]));
                dc.PSSetSamplers(0, Some(&[Some(sampler.clone())]));
                dc.RSSetViewports(Some(&[D3D11_VIEWPORT {
                    Width: window_size.width as f32,
                    Height: window_size.height as f32,
                    MaxDepth: 1.0,
                    ..Default::default()
                }]));
                dc.DrawIndexed(6, 0, 0);
                swap_chain.Present(1, 0).unwrap();
            },
            Event::WindowEvent {
                event: WindowEvent::CloseRequested,
                ..
            } => {
                *control_flow = ControlFlow::Exit;
            }
            _ => {}
        }
    });
}