use crate::bridge::ffi;
use crate::point::Point;
use crate::rect::Rect;
use std::ops::{Index, IndexMut, Mul};
#[repr(i32)]
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
pub enum ScaleToFit {
Fill = 0,
Start = 1,
Center = 2,
End = 3,
}
pub mod matrix_type {
#![allow(dead_code)]
pub const IDENTITY: u32 = 0;
pub const TRANSLATE: u32 = 0x01;
pub const SCALE: u32 = 0x02;
pub const AFFINE: u32 = 0x04;
pub const PERSPECTIVE: u32 = 0x08;
}
pub mod coeff {
pub const M_SCALE_X: usize = 0;
pub const M_SKEW_X: usize = 1;
pub const M_TRANS_X: usize = 2;
pub const M_SKEW_Y: usize = 3;
pub const M_SCALE_Y: usize = 4;
pub const M_TRANS_Y: usize = 5;
pub const M_PERSP_0: usize = 6;
pub const M_PERSP_1: usize = 7;
pub const M_PERSP_2: usize = 8;
}
#[derive(Debug, Clone, Copy)]
pub struct Matrix {
pub mat: [f32; 9],
}
impl Matrix {
pub const IDENTITY: Self = Self {
mat: [1.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 1.0],
};
#[inline]
pub const fn identity() -> Self {
Self::IDENTITY
}
pub fn invalid() -> Self {
let x = f32::MAX;
Self { mat: [x; 9] }
}
#[inline]
pub fn scale(sx: f32, sy: f32) -> Self {
let mut m = Self::IDENTITY;
m.set_scale(sx, sy);
m
}
#[inline]
pub fn translate(dx: f32, dy: f32) -> Self {
let mut m = Self::IDENTITY;
m.set_translate(dx, dy);
m
}
pub fn rotate_deg(degrees: f32) -> Self {
let mut m = Self::IDENTITY;
m.set_rotate(degrees);
m
}
#[inline]
pub fn make_all(
scale_x: f32,
skew_x: f32,
trans_x: f32,
skew_y: f32,
scale_y: f32,
trans_y: f32,
pers0: f32,
pers1: f32,
pers2: f32,
) -> Self {
let mut m = Self::IDENTITY;
m.set_all(
scale_x, skew_x, trans_x, skew_y, scale_y, trans_y, pers0, pers1, pers2,
);
m
}
#[inline]
pub const fn from_row_major_9(mat: [f32; 9]) -> Self {
Self { mat }
}
#[inline]
pub fn concat(a: &Matrix, b: &Matrix) -> Matrix {
let mut out = Self::IDENTITY;
ffi::matrix_set_concat(out.mat.as_mut_slice(), a.mat.as_slice(), b.mat.as_slice());
out
}
#[inline]
pub fn reset(&mut self) -> &mut Self {
ffi::matrix_reset(self.mat.as_mut_slice());
self
}
#[inline]
pub fn set_identity(&mut self) -> &mut Self {
self.reset()
}
pub fn set_all(
&mut self,
scale_x: f32,
skew_x: f32,
trans_x: f32,
skew_y: f32,
scale_y: f32,
trans_y: f32,
pers0: f32,
pers1: f32,
pers2: f32,
) -> &mut Self {
ffi::matrix_set_all(
self.mat.as_mut_slice(),
scale_x, skew_x, trans_x, skew_y, scale_y, trans_y, pers0, pers1, pers2,
);
self
}
#[inline]
pub fn set_translate(&mut self, dx: f32, dy: f32) -> &mut Self {
ffi::matrix_set_translate(self.mat.as_mut_slice(), dx, dy);
self
}
#[inline]
pub fn set_scale(&mut self, sx: f32, sy: f32) -> &mut Self {
ffi::matrix_set_scale(self.mat.as_mut_slice(), sx, sy);
self
}
#[inline]
pub fn set_scale_pivot(&mut self, sx: f32, sy: f32, px: f32, py: f32) -> &mut Self {
ffi::matrix_set_scale_pivot(self.mat.as_mut_slice(), sx, sy, px, py);
self
}
#[inline]
pub fn set_rotate(&mut self, degrees: f32) -> &mut Self {
ffi::matrix_set_rotate(self.mat.as_mut_slice(), degrees);
self
}
#[inline]
pub fn set_rotate_pivot(&mut self, degrees: f32, px: f32, py: f32) -> &mut Self {
ffi::matrix_set_rotate_pivot(self.mat.as_mut_slice(), degrees, px, py);
self
}
#[inline]
pub fn set_sin_cos(&mut self, sin_v: f32, cos_v: f32) -> &mut Self {
ffi::matrix_set_sin_cos(self.mat.as_mut_slice(), sin_v, cos_v);
self
}
#[inline]
pub fn set_sin_cos_pivot(&mut self, sin_v: f32, cos_v: f32, px: f32, py: f32) -> &mut Self {
ffi::matrix_set_sin_cos_pivot(self.mat.as_mut_slice(), sin_v, cos_v, px, py);
self
}
#[inline]
pub fn set_skew(&mut self, kx: f32, ky: f32) -> &mut Self {
ffi::matrix_set_skew(self.mat.as_mut_slice(), kx, ky);
self
}
#[inline]
pub fn set_skew_pivot(&mut self, kx: f32, ky: f32, px: f32, py: f32) -> &mut Self {
ffi::matrix_set_skew_pivot(self.mat.as_mut_slice(), kx, ky, px, py);
self
}
#[inline]
pub fn set_scale_translate(&mut self, sx: f32, sy: f32, tx: f32, ty: f32) -> &mut Self {
ffi::matrix_set_scale_translate(self.mat.as_mut_slice(), sx, sy, tx, ty);
self
}
#[inline]
pub fn set_concat(&mut self, a: &Matrix, b: &Matrix) -> &mut Self {
ffi::matrix_set_concat(
self.mat.as_mut_slice(),
a.mat.as_slice(),
b.mat.as_slice(),
);
self
}
pub fn set_rect_to_rect(&mut self, src: &Rect, dst: &Rect, stf: ScaleToFit) -> bool {
let sr: ffi::Rect = (*src).into();
let dr: ffi::Rect = (*dst).into();
ffi::matrix_set_rect_to_rect(self.mat.as_mut_slice(), &sr, &dr, stf as i32)
}
#[inline]
pub fn pre_translate(&mut self, dx: f32, dy: f32) -> &mut Self {
ffi::matrix_pre_translate(self.mat.as_mut_slice(), dx, dy);
self
}
#[inline]
pub fn pre_scale(&mut self, sx: f32, sy: f32) -> &mut Self {
ffi::matrix_pre_scale(self.mat.as_mut_slice(), sx, sy);
self
}
#[inline]
pub fn pre_scale_pivot(&mut self, sx: f32, sy: f32, px: f32, py: f32) -> &mut Self {
ffi::matrix_pre_scale_pivot(self.mat.as_mut_slice(), sx, sy, px, py);
self
}
#[inline]
pub fn pre_rotate(&mut self, degrees: f32) -> &mut Self {
ffi::matrix_pre_rotate(self.mat.as_mut_slice(), degrees);
self
}
#[inline]
pub fn pre_rotate_pivot(&mut self, degrees: f32, px: f32, py: f32) -> &mut Self {
ffi::matrix_pre_rotate_pivot(self.mat.as_mut_slice(), degrees, px, py);
self
}
#[inline]
pub fn pre_skew(&mut self, kx: f32, ky: f32) -> &mut Self {
ffi::matrix_pre_skew(self.mat.as_mut_slice(), kx, ky);
self
}
#[inline]
pub fn pre_skew_pivot(&mut self, kx: f32, ky: f32, px: f32, py: f32) -> &mut Self {
ffi::matrix_pre_skew_pivot(self.mat.as_mut_slice(), kx, ky, px, py);
self
}
#[inline]
pub fn pre_concat(&mut self, other: &Matrix) -> &mut Self {
ffi::matrix_pre_concat(self.mat.as_mut_slice(), other.mat.as_slice());
self
}
#[inline]
pub fn post_translate(&mut self, dx: f32, dy: f32) -> &mut Self {
ffi::matrix_post_translate(self.mat.as_mut_slice(), dx, dy);
self
}
#[inline]
pub fn post_scale(&mut self, sx: f32, sy: f32) -> &mut Self {
ffi::matrix_post_scale(self.mat.as_mut_slice(), sx, sy);
self
}
#[inline]
pub fn post_scale_pivot(&mut self, sx: f32, sy: f32, px: f32, py: f32) -> &mut Self {
ffi::matrix_post_scale_pivot(self.mat.as_mut_slice(), sx, sy, px, py);
self
}
#[inline]
pub fn post_rotate(&mut self, degrees: f32) -> &mut Self {
ffi::matrix_post_rotate(self.mat.as_mut_slice(), degrees);
self
}
#[inline]
pub fn post_rotate_pivot(&mut self, degrees: f32, px: f32, py: f32) -> &mut Self {
ffi::matrix_post_rotate_pivot(self.mat.as_mut_slice(), degrees, px, py);
self
}
#[inline]
pub fn post_skew(&mut self, kx: f32, ky: f32) -> &mut Self {
ffi::matrix_post_skew(self.mat.as_mut_slice(), kx, ky);
self
}
#[inline]
pub fn post_skew_pivot(&mut self, kx: f32, ky: f32, px: f32, py: f32) -> &mut Self {
ffi::matrix_post_skew_pivot(self.mat.as_mut_slice(), kx, ky, px, py);
self
}
#[inline]
pub fn post_concat(&mut self, other: &Matrix) -> &mut Self {
ffi::matrix_post_concat(self.mat.as_mut_slice(), other.mat.as_slice());
self
}
#[inline]
pub fn get_type(&self) -> u32 {
ffi::matrix_get_type(self.mat.as_slice())
}
#[inline]
pub fn is_identity(&self) -> bool {
ffi::matrix_is_identity(self.mat.as_slice())
}
#[inline]
pub fn is_scale_translate(&self) -> bool {
ffi::matrix_is_scale_translate_matrix(self.mat.as_slice())
}
#[inline]
pub fn rect_stays_rect(&self) -> bool {
ffi::matrix_rect_stays_rect(self.mat.as_slice())
}
#[inline]
pub fn preserves_axis_alignment(&self) -> bool {
self.rect_stays_rect()
}
#[inline]
pub fn has_perspective(&self) -> bool {
ffi::matrix_has_perspective(self.mat.as_slice())
}
#[inline]
pub fn is_finite(&self) -> bool {
ffi::matrix_is_finite_matrix(self.mat.as_slice())
}
#[inline]
pub fn get_scale_x(&self) -> f32 {
self.mat[coeff::M_SCALE_X]
}
#[inline]
pub fn get_skew_x(&self) -> f32 {
self.mat[coeff::M_SKEW_X]
}
#[inline]
pub fn get_translate_x(&self) -> f32 {
self.mat[coeff::M_TRANS_X]
}
#[inline]
pub fn get_skew_y(&self) -> f32 {
self.mat[coeff::M_SKEW_Y]
}
#[inline]
pub fn get_scale_y(&self) -> f32 {
self.mat[coeff::M_SCALE_Y]
}
#[inline]
pub fn get_translate_y(&self) -> f32 {
self.mat[coeff::M_TRANS_Y]
}
#[inline]
pub fn get_persp_x(&self) -> f32 {
self.mat[coeff::M_PERSP_0]
}
#[inline]
pub fn get_persp_y(&self) -> f32 {
self.mat[coeff::M_PERSP_1]
}
#[inline]
pub fn get_persp_z(&self) -> f32 {
self.mat[coeff::M_PERSP_2]
}
#[inline]
pub fn get(&self, index: usize) -> f32 {
self.mat[index]
}
#[inline]
pub fn set_coeff(&mut self, index: usize, value: f32) -> &mut Self {
self.mat[index] = value;
self
}
pub fn invert_to(&self, out_or_inverse: &mut Matrix) -> bool {
ffi::matrix_invert(
self.mat.as_slice(),
out_or_inverse.mat.as_mut_slice(),
)
}
pub fn try_inverse(&self) -> Option<Matrix> {
let mut out = Self::IDENTITY;
if self.invert_to(&mut out) {
Some(out)
} else {
None
}
}
#[inline]
pub fn map_xy(&self, x: f32, y: f32) -> Point {
let mut p = ffi::Point { fX: 0.0, fY: 0.0 };
ffi::matrix_map_xy(self.mat.as_slice(), x, y, &mut p);
p.into()
}
#[inline]
pub fn map_point(&self, p: Point) -> Point {
self.map_xy(p.x, p.y)
}
pub fn map_homogeneous(&self, x: f32, y: f32, z: f32) -> [f32; 3] {
let m = &self.mat;
[
m[0] * x + m[1] * y + m[2] * z,
m[3] * x + m[4] * y + m[5] * z,
m[6] * x + m[7] * y + m[8] * z,
]
}
pub fn map_points(&self, dst: &mut [Point], src: &[Point]) {
let n = src.len().min(dst.len());
for i in 0..n {
dst[i] = self.map_point(src[i]);
}
}
pub fn map_points_inplace(&self, pts: &mut [Point]) {
for p in pts.iter_mut() {
*p = self.map_point(*p);
}
}
#[inline]
pub fn map_origin(&self) -> Point {
let mut p = ffi::Point { fX: 0.0, fY: 0.0 };
ffi::matrix_map_origin(self.mat.as_slice(), &mut p);
p.into()
}
pub fn map_rect(&self, src: &Rect) -> (Rect, bool) {
let mut d = ffi::Rect {
fLeft: 0.0,
fTop: 0.0,
fRight: 0.0,
fBottom: 0.0,
};
let s: ffi::Rect = (*src).into();
let axis = ffi::matrix_map_rect(self.mat.as_slice(), &s, &mut d);
(d.into(), axis)
}
pub fn map_rect_scale_translate(&self, src: &Rect) -> Rect {
let mut d = ffi::Rect {
fLeft: 0.0,
fTop: 0.0,
fRight: 0.0,
fBottom: 0.0,
};
let s: ffi::Rect = (*src).into();
ffi::matrix_map_rect_scale_translate(self.mat.as_slice(), &s, &mut d);
d.into()
}
#[inline]
pub fn get_min_scale(&self) -> f32 {
ffi::matrix_get_min_scale(self.mat.as_slice())
}
#[inline]
pub fn get_max_scale(&self) -> f32 {
ffi::matrix_get_max_scale(self.mat.as_slice())
}
pub fn get_min_max_scales(&self) -> Option<(f32, f32)> {
let mut a = 0.0f32;
let mut b = 0.0f32;
if ffi::matrix_get_min_max_scales(self.mat.as_slice(), &mut a, &mut b) {
Some((a, b))
} else {
None
}
}
pub fn write_to_memory(&self, buf: &mut [u8]) -> usize {
ffi::matrix_write_to_memory(self.mat.as_slice(), buf)
}
pub fn read_from_memory(&mut self, buf: &[u8]) -> usize {
ffi::matrix_read_from_memory(self.mat.as_mut_slice(), buf)
}
}
impl Default for Matrix {
fn default() -> Self {
Self::IDENTITY
}
}
impl PartialEq for Matrix {
fn eq(&self, other: &Self) -> bool {
ffi::matrix_equals(self.mat.as_slice(), other.mat.as_slice())
}
}
impl Eq for Matrix {}
impl Index<usize> for Matrix {
type Output = f32;
fn index(&self, index: usize) -> &f32 {
&self.mat[index]
}
}
impl IndexMut<usize> for Matrix {
fn index_mut(&mut self, index: usize) -> &mut f32 {
&mut self.mat[index]
}
}
impl Mul for Matrix {
type Output = Matrix;
fn mul(self, rhs: Matrix) -> Matrix {
Matrix::concat(&self, &rhs)
}
}
impl Mul<&Matrix> for Matrix {
type Output = Matrix;
fn mul(self, rhs: &Matrix) -> Matrix {
Matrix::concat(&self, rhs)
}
}
impl Mul<Matrix> for &Matrix {
type Output = Matrix;
fn mul(self, rhs: Matrix) -> Matrix {
Matrix::concat(self, &rhs)
}
}
impl Mul for &Matrix {
type Output = Matrix;
fn mul(self, rhs: &Matrix) -> Matrix {
Matrix::concat(self, rhs)
}
}