use bitflags::bitflags; use crate::CurrentContextWithFns; use crate::data_types::{Dimens, Vec2}; /// Sets the viewport. /// /// The `u32` values in `position` and `size` must fit in `i32`s. /// /// # Errors /// Returns `Err` if any value in `position` or `size` does not fit into a `i32`. pub fn set_viewport( current_context: &CurrentContextWithFns<'_>, position: &Vec2, size: &Dimens, ) -> Result<(), SetViewportError> { let position = Vec2:: { x: position.x.try_into().map_err(|_| { SetViewportError::PositionXValueTooLarge { value: position.x, max_value: crate::sys::types::GLint::MAX as u32, } })?, y: position.y.try_into().map_err(|_| { SetViewportError::PositionYValueTooLarge { value: position.y, max_value: crate::sys::types::GLint::MAX as u32, } })?, }; let size = Dimens:: { width: size.width.try_into().map_err(|_| { SetViewportError::SizeWidthValueTooLarge { value: size.width, max_value: crate::sys::types::GLsizei::MAX as u32, } })?, height: size.height.try_into().map_err(|_| { SetViewportError::SizeHeightValueTooLarge { value: size.height, max_value: crate::sys::types::GLsizei::MAX as u32, } })?, }; unsafe { current_context .fns() .Viewport(position.x, position.y, size.width, size.height); } Ok(()) } pub fn get_viewport( current_context: &CurrentContextWithFns<'_>, ) -> (Vec2, Dimens) { let mut values = [0i32; 4]; unsafe { current_context .fns() .GetIntegerv(crate::sys::VIEWPORT, values.as_mut_ptr()); } let [x, y, width, height] = values; let pos = Vec2:: { x: x.try_into().expect("Negative viewport x coordinate"), y: y.try_into().expect("Negative viewport y coordinate"), }; let size = Dimens:: { width: width.try_into().expect("Negative viewport width"), height: height.try_into().expect("Negative viewport height"), }; (pos, size) } pub fn clear_buffers(current_context: &CurrentContextWithFns<'_>, mask: BufferClearMask) { unsafe { current_context.fns().Clear(mask.bits()); } } pub fn set_polygon_mode( current_context: &CurrentContextWithFns<'_>, face: impl Into, mode: impl Into, ) { unsafe { current_context .fns() .PolygonMode(face.into() as u32, mode.into() as u32); } } pub fn enable(current_context: &CurrentContextWithFns<'_>, capacity: Capability) { unsafe { current_context.fns().Enable(capacity as u32); } } pub fn disable(current_context: &CurrentContextWithFns<'_>, capability: Capability) { unsafe { current_context.fns().Disable(capability as u32); } } pub fn set_enabled( current_context: &CurrentContextWithFns<'_>, capability: Capability, enabled: bool, ) { if enabled { enable(current_context, capability); } else { disable(current_context, capability); } } #[must_use] pub fn get_context_flags(current_context: &CurrentContextWithFns<'_>) -> ContextFlags { let mut context_flags = crate::sys::types::GLint::default(); unsafe { current_context .fns() .GetIntegerv(crate::sys::CONTEXT_FLAGS, &raw mut context_flags); } ContextFlags::from_bits_truncate(context_flags.cast_unsigned()) } /// Defines a rectangle, called the scissor box, in window coordinates. pub fn define_scissor_box( current_context: &CurrentContextWithFns<'_>, lower_left_corner_pos: Vec2, size: Dimens, ) { let lower_left_corner_pos = Vec2:: { x: lower_left_corner_pos.x.into(), y: lower_left_corner_pos.y.into(), }; let size = Dimens:: { width: size.width.into(), height: size.height.into(), }; unsafe { current_context.fns().Scissor( lower_left_corner_pos.x, lower_left_corner_pos.y, size.width, size.height, ); } } bitflags! { #[derive(Debug, Clone, Copy)] pub struct BufferClearMask: u32 { const COLOR = crate::sys::COLOR_BUFFER_BIT; const DEPTH = crate::sys::DEPTH_BUFFER_BIT; const STENCIL = crate::sys::STENCIL_BUFFER_BIT; } } #[derive(Debug, Clone, Copy)] #[repr(u32)] #[non_exhaustive] pub enum Capability { DepthTest = crate::sys::DEPTH_TEST, ScissorTest = crate::sys::SCISSOR_TEST, MultiSample = crate::sys::MULTISAMPLE, DebugOutput = crate::sys::DEBUG_OUTPUT, DebugOutputSynchronous = crate::sys::DEBUG_OUTPUT_SYNCHRONOUS, Blend = crate::sys::BLEND, CullFace = crate::sys::CULL_FACE, } #[derive(Debug)] #[repr(u32)] pub enum PolygonMode { Point = crate::sys::POINT, Line = crate::sys::LINE, Fill = crate::sys::FILL, } #[derive(Debug)] #[repr(u32)] pub enum PolygonModeFace { Front = crate::sys::FRONT, Back = crate::sys::BACK, FrontAndBack = crate::sys::FRONT_AND_BACK, } bitflags! { #[derive(Debug, Clone, Copy)] pub struct ContextFlags: u32 { const FORWARD_COMPATIBLE = crate::sys::CONTEXT_FLAG_FORWARD_COMPATIBLE_BIT; const DEBUG = crate::sys::CONTEXT_FLAG_DEBUG_BIT; const ROBUST_ACCESS = crate::sys::CONTEXT_FLAG_ROBUST_ACCESS_BIT; } } #[derive(Debug, thiserror::Error)] pub enum SetViewportError { #[error("Position X value ({value}) is too large. Must be < {max_value}")] PositionXValueTooLarge { value: u32, max_value: u32 }, #[error("Position Y value ({value}) is too large. Must be < {max_value}")] PositionYValueTooLarge { value: u32, max_value: u32 }, #[error("Size width value ({value}) is too large. Must be < {max_value}")] SizeWidthValueTooLarge { value: u32, max_value: u32 }, #[error("Size height value ({value}) is too large. Must be < {max_value}")] SizeHeightValueTooLarge { value: u32, max_value: u32 }, }