pnte 0.3.3

2D Graphics library for Windows in Rust
Documentation
use super::*;
use windows::Win32::{
    Graphics::Direct2D::Common::*, Graphics::Direct2D::*, Graphics::Direct3D11::*,
    Graphics::Dxgi::*,
};
use windows::core::Interface;

#[derive(Clone, PartialEq, Eq, Debug)]
pub struct RenderTarget(ID2D1Bitmap1);

impl Target for RenderTarget {
    #[inline]
    fn bitmap(&self) -> &ID2D1Bitmap1 {
        &self.0
    }

    #[inline]
    fn size(&self) -> Size<f32> {
        unsafe { self.0.GetSize().into() }
    }

    #[inline]
    fn pixel_size(&self) -> Size<u32> {
        unsafe { self.0.GetPixelSize().into() }
    }
}

#[derive(Clone, Debug)]
pub struct Direct3D11 {
    d2d1_factory: ID2D1Factory6,
    d2d1_device: ID2D1Device5,
}

impl Direct3D11 {
    pub fn new<T>(d3d11_device: &T) -> Result<Self>
    where
        T: Interface,
    {
        let d3d11_device: ID3D11Device = d3d11_device.cast()?;
        let d2d1_factory: ID2D1Factory6 =
            unsafe { D2D1CreateFactory(D2D1_FACTORY_TYPE_MULTI_THREADED, None)? };
        let dxgi_device: IDXGIDevice = d3d11_device.cast()?;
        let d2d1_device: ID2D1Device5 = unsafe { d2d1_factory.CreateDevice(&dxgi_device)? };
        Ok(Self {
            d2d1_factory,
            d2d1_device,
        })
    }

    pub(crate) fn create_render_target_from_swap_chain(
        &self,
        ctx: &ID2D1DeviceContext5,
        swap_chain: &IDXGISwapChain1,
    ) -> Result<RenderTarget> {
        unsafe {
            let desc = swap_chain.GetDesc1()?;
            let surface: IDXGISurface = swap_chain.GetBuffer(0)?;
            let bitmap = ctx.CreateBitmapFromDxgiSurface(
                &surface,
                Some(&D2D1_BITMAP_PROPERTIES1 {
                    pixelFormat: D2D1_PIXEL_FORMAT {
                        format: desc.Format,
                        alphaMode: D2D1_ALPHA_MODE_IGNORE,
                    },
                    bitmapOptions: D2D1_BITMAP_OPTIONS_TARGET | D2D1_BITMAP_OPTIONS_CANNOT_DRAW,
                    dpiX: 96.0,
                    dpiY: 96.0,
                    ..Default::default()
                }),
            )?;
            Ok(RenderTarget(bitmap))
        }
    }
}

impl Context<Direct3D11> {
    pub fn create_render_target<T>(&self, target: &T) -> Result<RenderTarget>
    where
        T: Interface,
    {
        match target.cast::<IDXGISwapChain1>() {
            Ok(swap_chain) => self.create_render_target_from_swap_chain(&swap_chain),
            _ => match target.cast::<ID3D11Texture2D>() {
                Ok(texture) => self.create_render_target_from_texture(&texture),
                _ => Err(Error::NoInterface),
            },
        }
    }

    fn create_render_target_from_swap_chain(
        &self,
        swap_chain: &IDXGISwapChain1,
    ) -> Result<RenderTarget> {
        self.backend
            .create_render_target_from_swap_chain(&self.d2d1_device_context, swap_chain)
    }

    fn create_render_target_from_texture(&self, texture: &ID3D11Texture2D) -> Result<RenderTarget> {
        unsafe {
            let mut desc = D3D11_TEXTURE2D_DESC::default();
            texture.GetDesc(&mut desc);
            let surface: IDXGISurface = texture.cast().unwrap();
            let bitmap = self.d2d1_device_context.CreateBitmapFromDxgiSurface(
                &surface,
                Some(&D2D1_BITMAP_PROPERTIES1 {
                    pixelFormat: D2D1_PIXEL_FORMAT {
                        format: desc.Format,
                        alphaMode: D2D1_ALPHA_MODE_PREMULTIPLIED,
                    },
                    bitmapOptions: D2D1_BITMAP_OPTIONS_TARGET | D2D1_BITMAP_OPTIONS_CANNOT_DRAW,
                    ..Default::default()
                }),
            )?;
            Ok(RenderTarget(bitmap))
        }
    }
}

impl Backend for Direct3D11 {
    type RenderTarget = RenderTarget;

    #[inline]
    fn d2d1_factory(&self) -> &ID2D1Factory6 {
        &self.d2d1_factory
    }

    #[inline]
    fn d2d1_device(&self) -> &ID2D1Device5 {
        &self.d2d1_device
    }
}