d3d11 0.2.0

Safe(r) bindings to the D3D11 API
Documentation
use std::mem::transmute;

use bon::Builder;
use d3d11_ffi::Direct3D11::D3D11_VIEWPORT;
use static_assertions::assert_eq_size;

use crate::{util::OptionalParam, RasterizerState};

use super::DeviceContext;

#[cfg_attr(feature = "profiling", profiling::all_functions)]
impl DeviceContext {
    pub fn rasterizer_set_viewports(&self, viewports: &[Viewport]) {
        unsafe {
            self.0.RSSetViewports(Some(transmute(viewports)));
        }
    }

    pub fn rasterizer_get_viewports(&self) -> [Viewport; 8] {
        let mut viewports: [D3D11_VIEWPORT; 8] = std::array::from_fn(|_| Default::default());
        unsafe {
            self.0.RSGetViewports(&mut 8, Some(viewports.as_mut_ptr()));
            viewports.map(|v| transmute(v))
        }
    }

    pub fn rasterizer_set_scissor_rects(&self, rects: &[Rect]) {
        unsafe {
            self.0.RSSetScissorRects(Some(transmute(rects)));
        }
    }

    pub fn rasterizer_set_state(&self, state: impl OptionalParam<Output = RasterizerState>) {
        unsafe {
            self.0.RSSetState(state.as_option().map(|s| &s.0));
        }
    }
}

#[repr(C)]
#[derive(Clone, Debug, Builder)]
pub struct Viewport {
    #[builder(default = 0.0)]
    pub top_left_x: f32,
    #[builder(default = 0.0)]
    pub top_left_y: f32,
    pub width: f32,
    pub height: f32,
    #[builder(default = 0.0)]
    pub min_depth: f32,
    #[builder(default = 1.0)]
    pub max_depth: f32,
}
assert_eq_size!(Viewport, D3D11_VIEWPORT);

impl Viewport {
    /// Scales the viewport to fit the given mip level (eg. 0 is full size, 1 is half size, etc.)
    ///
    /// Only the width and height are scaled, the top left x and y are not.
    pub fn scale_to_mip(&self, mip: u32) -> Self {
        let scale = (1 << mip) as f32;
        Self {
            top_left_x: self.top_left_x,
            top_left_y: self.top_left_y,
            width: self.width / scale,
            height: self.height / scale,
            min_depth: self.min_depth,
            max_depth: self.max_depth,
        }
    }
}

impl Default for Viewport {
    fn default() -> Self {
        Self {
            top_left_x: 0.0,
            top_left_y: 0.0,
            width: 0.0,
            height: 0.0,
            min_depth: 0.0,
            max_depth: 0.0,
        }
    }
}

#[repr(C)]
#[derive(Clone, Debug, Builder)]
pub struct Rect {
    pub left: i32,
    pub top: i32,
    pub right: i32,
    pub bottom: i32,
}
assert_eq_size!(Rect, d3d11_ffi::Foundation::RECT);