use core::marker::Sized;
use core::ops::{Add, BitAnd, BitOr, Div, Mul, Sub};
pub type Vertex2F = Vertex2D<Scaled>;
pub type Vertex2II = Vertex2D<Fixed>;
pub type GlobalTranslation = Vertex2D<ForGlobalTranslate>;
pub type WidgetPos = Vertex2D<ForCoprocessorWidgets>;
pub type WidgetRect = Rect<ForCoprocessorWidgets>;
pub type ScissorPos = Vertex2D<ForScissorClip>;
pub type ScissorRect = Rect<ForScissorClip>;
#[derive(Debug, PartialEq, Eq, Clone, Copy)]
pub struct Vertex2D<S: CoordinateSystem> {
pub(crate) x: S::Dim,
pub(crate) y: S::Dim,
}
impl<S: CoordinateSystem> Vertex2D<S> {
#[inline]
pub fn new(x: S::Dim, y: S::Dim) -> Self {
Self {
x: S::mask_value(x),
y: S::mask_value(y),
}
}
#[inline]
pub fn coords(&self) -> (S::Dim, S::Dim) {
(self.x, self.y)
}
}
impl<S: CoordinateSystem> core::convert::From<(S::Dim, S::Dim)> for Vertex2D<S> {
fn from(coords: (S::Dim, S::Dim)) -> Self {
Self::new(coords.0, coords.1)
}
}
impl<S: CoordinateSystem> core::convert::From<Vertex2D<S>> for (S::Dim, S::Dim) {
fn from(vertex: Vertex2D<S>) -> Self {
vertex.coords()
}
}
#[derive(Debug, PartialEq, Eq, Clone, Copy)]
pub struct Rect<S: CoordinateSystem> {
pub(crate) x: S::Dim,
pub(crate) y: S::Dim,
pub(crate) w: S::Dim,
pub(crate) h: S::Dim,
}
impl<S: CoordinateSystem> Rect<S> {
#[inline]
pub fn new(x: S::Dim, y: S::Dim, w: S::Dim, h: S::Dim) -> Self {
Self {
x: x,
y: y,
w: w,
h: h,
}
}
#[inline]
pub fn with_bounds(top_left: Vertex2D<S>, bottom_right: Vertex2D<S>) -> Self {
Self {
x: top_left.x,
y: top_left.y,
w: bottom_right.x - top_left.x,
h: bottom_right.y - top_left.y,
}
}
#[inline]
pub fn top_left(&self) -> Vertex2D<S> {
Vertex2D::new(self.x, self.y)
}
#[inline]
pub fn bottom_right(&self) -> Vertex2D<S> {
Vertex2D::new(self.x + self.w, self.y + self.h)
}
#[inline]
pub fn size(&self) -> (S::Dim, S::Dim) {
(self.w, self.h)
}
#[inline]
pub fn bounds(&self) -> (Vertex2D<S>, Vertex2D<S>) {
let top_left = Vertex2D::new(self.x, self.y);
let bottom_right = Vertex2D::new(self.x + self.w, self.y + self.h);
(top_left, bottom_right)
}
}
impl<S: CoordinateSystem> core::convert::From<(S::Dim, S::Dim, S::Dim, S::Dim)> for Rect<S> {
fn from(coords: (S::Dim, S::Dim, S::Dim, S::Dim)) -> Self {
Self::new(coords.0, coords.1, coords.2, coords.3)
}
}
impl<S: CoordinateSystem, V: Into<Vertex2D<S>>> core::convert::From<(V, S::Dim, S::Dim)>
for Rect<S>
{
fn from(coords: (V, S::Dim, S::Dim)) -> Self {
let tl: Vertex2D<S> = coords.0.into();
Self::new(tl.x, tl.y, coords.1, coords.2)
}
}
impl<S: CoordinateSystem, V1: Into<Vertex2D<S>>, V2: Into<Vertex2D<S>>>
core::convert::From<(V1, V2)> for Rect<S>
{
fn from(coords: (V1, V2)) -> Self {
Self::with_bounds(coords.0.into(), coords.1.into())
}
}
impl<S: CoordinateSystem> core::convert::From<Rect<S>> for (S::Dim, S::Dim, S::Dim, S::Dim) {
fn from(rect: Rect<S>) -> (S::Dim, S::Dim, S::Dim, S::Dim) {
(rect.x, rect.y, rect.w, rect.h)
}
}
impl<S: CoordinateSystem> core::convert::From<Rect<S>> for (Vertex2D<S>, Vertex2D<S>) {
fn from(rect: Rect<S>) -> (Vertex2D<S>, Vertex2D<S>) {
rect.bounds()
}
}
impl<S: CoordinateSystem> core::convert::From<Rect<S>> for ((S::Dim, S::Dim), (S::Dim, S::Dim)) {
fn from(rect: Rect<S>) -> ((S::Dim, S::Dim), (S::Dim, S::Dim)) {
let bounds = rect.bounds();
(bounds.0.into(), bounds.1.into())
}
}
impl<S: CoordinateSystem> core::convert::From<Rect<S>> for (Vertex2D<S>, S::Dim, S::Dim) {
fn from(rect: Rect<S>) -> (Vertex2D<S>, S::Dim, S::Dim) {
(Vertex2D::new(rect.x, rect.y), rect.w, rect.h)
}
}
pub trait CoordinateSystem {
type Dim: Sized
+ Clone
+ Copy
+ Add<Output = Self::Dim>
+ Sub<Output = Self::Dim>
+ Mul<Output = Self::Dim>
+ Div<Output = Self::Dim>
+ BitAnd<Output = Self::Dim>
+ BitOr<Output = Self::Dim>;
fn mask_value(v: Self::Dim) -> Self::Dim;
}
pub enum Scaled {}
impl CoordinateSystem for Scaled {
type Dim = i16;
fn mask_value(v: Self::Dim) -> Self::Dim {
((v as u16) & 0b11111111111111) as i16
}
}
pub enum Fixed {}
impl CoordinateSystem for Fixed {
type Dim = u16;
fn mask_value(v: Self::Dim) -> Self::Dim {
v & 0b111111111
}
}
pub enum ForGlobalTranslate {}
impl CoordinateSystem for ForGlobalTranslate {
type Dim = i16;
fn mask_value(v: Self::Dim) -> Self::Dim {
v
}
}
pub enum ForCoprocessorWidgets {}
impl CoordinateSystem for ForCoprocessorWidgets {
type Dim = i16;
fn mask_value(v: Self::Dim) -> Self::Dim {
v
}
}
pub enum ForScissorClip {}
impl CoordinateSystem for ForScissorClip {
type Dim = u16;
fn mask_value(v: Self::Dim) -> Self::Dim {
v & 0b111111111111
}
}