baseview 0.2.2

Low-level windowing system geared towards making audio plugin UIs.
Documentation
use crate::gl::GlConfig;
use crate::wrappers::win32::window::{HWnd, WglContext};
use std::ffi::c_void;
use std::num::{NonZero, NonZeroI32};
use std::ptr::NonNull;
use windows_core::{Error, Result};
use windows_sys::Win32::Graphics::Gdi::{GetDC, HDC};
use windows_sys::Win32::Graphics::OpenGL::{
    wglCreateContext, ChoosePixelFormat, DescribePixelFormat, SetPixelFormat, SwapBuffers,
    PFD_DOUBLEBUFFER, PFD_DRAW_TO_WINDOW, PFD_MAIN_PLANE, PFD_SUPPORT_OPENGL, PFD_TYPE_RGBA,
    PIXELFORMATDESCRIPTOR,
};

pub struct OwnDeviceContext {
    inner: NonNull<c_void>,
}

impl OwnDeviceContext {
    pub(super) fn from_window(window: HWnd) -> Result<Self> {
        let dc = unsafe { GetDC(window.as_raw()) };

        let dc = NonNull::new(dc).ok_or_else(Error::from_thread)?;

        Ok(Self { inner: dc })
    }

    pub fn as_raw(&self) -> HDC {
        self.inner.as_ptr()
    }

    fn describe_pixel_format(&self, index: NonZeroI32) -> Result<PIXELFORMATDESCRIPTOR> {
        let mut desc = PIXELFORMATDESCRIPTOR {
            nSize: size_of::<PIXELFORMATDESCRIPTOR>() as u16,
            ..Default::default()
        };

        let result = unsafe {
            DescribePixelFormat(
                self.as_raw(),
                index.get(),
                size_of::<PIXELFORMATDESCRIPTOR>() as u32,
                &mut desc,
            )
        };

        if result == 0 {
            return Err(Error::from_thread());
        }

        Ok(desc)
    }

    pub fn set_pixel_format(&self, pixel_format: &PixelFormat) -> Result<()> {
        let desc = pixel_format.to_raw_descriptor();
        let index = unsafe { ChoosePixelFormat(self.as_raw(), &desc) };
        let Some(index) = NonZero::new(index) else { return Err(Error::from_thread()) };

        let result = unsafe { SetPixelFormat(self.as_raw(), index.get(), &desc) };

        if result == 0 {
            return Err(Error::from_thread());
        }

        Ok(())
    }

    pub fn set_pixel_format_from_index(&self, index: NonZeroI32) -> Result<()> {
        let desc = self.describe_pixel_format(index)?;
        let result = unsafe { SetPixelFormat(self.as_raw(), index.get(), &desc) };

        if result == 0 {
            return Err(Error::from_thread());
        }

        Ok(())
    }

    pub fn create_wgl_context(&self) -> Result<WglContext> {
        let ctx = unsafe { wglCreateContext(self.as_raw()) };
        let ctx = NonNull::new(ctx).ok_or_else(Error::from_thread)?;

        Ok(WglContext { inner: ctx })
    }

    pub fn swap_buffers(&self) -> Result<()> {
        let result = unsafe { SwapBuffers(self.as_raw()) };
        if result == 0 {
            return Err(Error::from_thread());
        }

        Ok(())
    }
}

#[derive(Copy, Clone)]
pub struct PixelFormat {
    pub alpha_bits: u8,
    pub depth_bits: u8,
    pub stencil_bits: u8,
}

impl Default for PixelFormat {
    fn default() -> Self {
        Self { alpha_bits: 8, depth_bits: 24, stencil_bits: 8 }
    }
}

impl PixelFormat {
    pub fn from_config(config: &GlConfig) -> Self {
        Self {
            alpha_bits: config.alpha_bits,
            depth_bits: config.depth_bits,
            stencil_bits: config.stencil_bits,
        }
    }

    pub fn to_raw_descriptor(self) -> PIXELFORMATDESCRIPTOR {
        PIXELFORMATDESCRIPTOR {
            nSize: size_of::<PIXELFORMATDESCRIPTOR>() as u16,
            nVersion: 1,
            dwFlags: PFD_DRAW_TO_WINDOW | PFD_SUPPORT_OPENGL | PFD_DOUBLEBUFFER,
            iPixelType: PFD_TYPE_RGBA,
            cColorBits: 32,
            cAlphaBits: self.alpha_bits,
            cDepthBits: self.depth_bits,
            cStencilBits: self.stencil_bits,
            iLayerType: PFD_MAIN_PLANE as u8,
            ..Default::default()
        }
    }
}