use windows::Win32::Graphics::Direct2D::{
Common::{D2D_SIZE_F, D2D_SIZE_U},
ID2D1Bitmap, ID2D1BitmapRenderTarget, ID2D1RenderTarget, D2D1_COMPATIBLE_RENDER_TARGET_OPTIONS_NONE,
};
use super::{canvas::D2DCanvas, device::D2DDeviceContext};
use crate::{
base::Dimension,
canvas::CanvasBackend,
error::GraphicsError,
geometry::{FSize, ISize},
layer::LayerBackend,
};
const DEFAULT_DPI: f32 = 96.0;
#[derive(Clone, Debug)]
pub struct D2DLayer {
render_target: ID2D1BitmapRenderTarget,
}
impl Dimension for D2DLayer {
fn size(&self) -> FSize {
unsafe { self.render_target.GetSize().into() }
}
fn pixel_size(&self) -> ISize {
let size = unsafe { self.render_target.GetPixelSize() };
ISize::new(size.width as i32, size.height as i32)
}
}
impl LayerBackend for D2DLayer {
type DeviceContextType = D2DDeviceContext;
type CanvasType = D2DCanvas;
fn new(_context: Option<&Self::DeviceContextType>, width: usize, height: usize, canvas: &Self::CanvasType) -> Result<Self, GraphicsError> {
let render_target = canvas.render_target();
let (mut dpi_x, mut dpi_y) = (0.0, 0.0);
unsafe {
render_target.GetDpi(&mut dpi_x, &mut dpi_y);
}
let matrix = &canvas.get_matrix().matrix;
let size = D2D_SIZE_F {
width: width as f32,
height: height as f32,
};
let pixel_size = D2D_SIZE_U {
width: (width as f32 * dpi_x * matrix.M11 / DEFAULT_DPI).ceil() as u32,
height: (height as f32 * dpi_y * matrix.M22 / DEFAULT_DPI).ceil() as u32,
};
let render_target = unsafe {
render_target
.CreateCompatibleRenderTarget(Some(&size), Some(&pixel_size), None, D2D1_COMPATIBLE_RENDER_TARGET_OPTIONS_NONE)
.map_err(|err| GraphicsError::CreationFailed(err.to_string()))?
};
Ok(Self {
render_target,
})
}
}
impl D2DLayer {
pub(super) fn render_target(&self) -> &ID2D1RenderTarget {
&self.render_target
}
pub(super) fn bitmap(&self) -> Option<ID2D1Bitmap> {
unsafe { self.render_target.GetBitmap().ok() }
}
}