use crate::mesh::Vertex;
use nalgebra::Matrix4;
use palette::{encoding::srgb::Srgb, rgb::Rgb, Hsv, RgbHue};
use std::iter;
fn identity() -> Matrix4<f32> {
Matrix4::new(
1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0,
)
}
pub type Tf = Transform;
#[derive(Copy, Clone, Debug)]
pub struct Transform {
spatial: Matrix4<f32>,
color: ColorTransform,
}
#[derive(Copy, Clone, Debug)]
enum ColorTransform {
Override(Hsv),
Delta(Hsv),
}
impl Default for ColorTransform {
fn default() -> ColorTransform {
ColorTransform::Delta(Hsv::new(0.0, 1.0, 1.0))
}
}
impl ColorTransform {
fn cons(self, other: ColorTransform) -> Self {
match (self, other) {
(_, ColorTransform::Override(color)) => ColorTransform::Override(color),
(ColorTransform::Override(color), ColorTransform::Delta(delta)) => {
ColorTransform::Override(Hsv::new(
color.hue + delta.hue,
color.saturation * delta.saturation,
color.value * delta.value,
))
}
(ColorTransform::Delta(delta_a), ColorTransform::Delta(delta_b)) => {
ColorTransform::Delta(Hsv::new(
delta_a.hue + delta_b.hue,
delta_a.saturation * delta_b.saturation,
delta_a.value * delta_b.value,
))
}
}
}
fn color(self) -> Hsv {
match self {
ColorTransform::Override(color) => color,
ColorTransform::Delta(delta) => {
let color = Hsv::new(0.0, 1.0, 1.0);
Hsv::new(
color.hue + delta.hue,
color.saturation * delta.saturation,
color.value * delta.value,
)
}
}
}
}
impl Transform {
pub(crate) fn cons(&self, other: Transform) -> Transform {
Transform {
spatial: self.spatial * other.spatial,
color: self.color.cons(other.color),
}
}
pub(crate) fn apply_to(&self, vertex: Vertex) -> Vertex {
self.spatial * vertex
}
pub(crate) fn get_color(&self) -> Rgb<Srgb, f32> {
Rgb::from(
ColorTransform::Override(Hsv::new(0.0, 1.0, 1.0))
.cons(self.color)
.color(),
)
}
pub fn t(x: f32, y: f32, z: f32) -> Self {
Self {
spatial: Translate::by(x, y, z),
..Self::default()
}
}
pub fn tx(x: f32) -> Self {
Self {
spatial: Translate::x(x),
..Self::default()
}
}
pub fn ty(y: f32) -> Self {
Self {
spatial: Translate::y(y),
..Self::default()
}
}
pub fn tz(z: f32) -> Self {
Self {
spatial: Translate::z(z),
..Self::default()
}
}
pub fn s(factor: f32) -> Self {
Self {
spatial: Scale::all(factor),
..Self::default()
}
}
pub fn sby(x: f32, y: f32, z: f32) -> Self {
Self {
spatial: Scale::by(x, y, z),
..Self::default()
}
}
pub fn rx(x: f32) -> Self {
Self {
spatial: Rotate::x(x),
..Self::default()
}
}
pub fn ry(y: f32) -> Self {
Self {
spatial: Rotate::y(y),
..Self::default()
}
}
pub fn rz(z: f32) -> Self {
Self {
spatial: Rotate::z(z),
..Self::default()
}
}
pub fn color(color: Hsv) -> Self {
Self {
color: ColorTransform::Override(color),
..Self::default()
}
}
pub fn hue(delta: impl Into<RgbHue<f32>>) -> Self {
Self {
color: ColorTransform::Delta(Hsv::new(delta, 1.0, 1.0)),
..Self::default()
}
}
pub fn saturation(factor: f32) -> Self {
Self {
color: ColorTransform::Delta(Hsv::new(0.0, factor, 1.0)),
..Self::default()
}
}
pub fn value(factor: f32) -> Self {
Self {
color: ColorTransform::Delta(Hsv::new(0.0, 1.0, factor)),
..Self::default()
}
}
fn cross(parents: Vec<Transform>, children: Vec<Transform>) -> Vec<Transform> {
let mut emitted = vec![];
emitted.reserve(parents.len() * children.len());
for parent in parents {
for child in &children {
emitted.push(parent.cons(*child));
}
}
emitted
}
fn coalesce(default: Option<Transform>, source: impl Iterator<Item = Transform>) -> Self {
source.fold(default.unwrap_or(Transform::default()), |prefix, suffix| {
prefix.cons(suffix)
})
}
fn stack(self, n: usize) -> Self {
Transform::coalesce(Some(self), iter::repeat(self).take(n))
}
}
impl Default for Transform {
fn default() -> Self {
Self {
spatial: identity(),
color: ColorTransform::default(),
}
}
}
#[derive(Debug)]
pub enum TransformArgument {
Single(Transform),
Many(Vec<Transform>),
}
#[macro_export]
macro_rules! tf {
($($transform:expr),+ $(,)*) => ({
let mut args: Vec<TransformArgument> = vec![];
$(args.push($transform.into());)*
args
});
}
impl Into<Vec<Transform>> for TransformArgument {
fn into(self) -> Vec<Transform> {
match self {
TransformArgument::Single(transform) => vec![transform],
TransformArgument::Many(transforms) => transforms,
}
}
}
impl From<Transform> for TransformArgument {
fn from(transform: Transform) -> Self {
TransformArgument::Single(transform)
}
}
impl From<Vec<Transform>> for TransformArgument {
fn from(transforms: Vec<Transform>) -> Self {
TransformArgument::Single(Transform::coalesce(None, transforms.into_iter()))
}
}
impl From<&[Transform]> for TransformArgument {
fn from(transforms: &[Transform]) -> Self {
TransformArgument::Single(Transform::coalesce(None, transforms.iter().map(|t| *t)))
}
}
impl From<Vec<TransformArgument>> for TransformArgument {
fn from(args: Vec<TransformArgument>) -> Self {
let mut emitted = vec![Transform::default()];
for arg in args {
emitted = Transform::cross(emitted, arg.into());
}
TransformArgument::Many(emitted)
}
}
impl From<Option<Transform>> for TransformArgument {
fn from(maybe_input: Option<Transform>) -> Self {
match maybe_input {
Some(input) => input.into(),
None => TransformArgument::Many(vec![]),
}
}
}
impl From<Vec<Replicate>> for TransformArgument {
fn from(replications: Vec<Replicate>) -> TransformArgument {
let mut emitted = vec![];
for replication in replications.into_iter().map(|r| -> Vec<Transform> {
let input: TransformArgument = r.into();
input.into()
}) {
emitted = if emitted.is_empty() {
replication
} else {
Transform::cross(emitted, replication)
};
}
TransformArgument::Many(emitted)
}
}
pub struct Replicate {
n: usize,
source: TransformArgument,
}
impl Replicate {
pub fn n(n: usize, source: impl Into<TransformArgument>) -> Self {
Self {
n,
source: source.into(),
}
}
}
impl Into<TransformArgument> for Replicate {
fn into(self) -> TransformArgument {
match self.source {
TransformArgument::Single(transform) => {
TransformArgument::Many((0..self.n).map(|i| transform.stack(i)).collect())
}
TransformArgument::Many(transforms) => TransformArgument::Many({
let mut emitted = vec![];
for transform in transforms {
for i in 0..self.n {
emitted.push(transform.stack(i));
}
}
emitted
}),
}
}
}
#[derive(Default, Clone, Copy, Debug)]
struct Translate;
impl Translate {
pub fn by(x: f32, y: f32, z: f32) -> Matrix4<f32> {
Matrix4::new(
1.0, 0.0, 0.0, x, 0.0, 1.0, 0.0, y, 0.0, 0.0, 1.0, z, 0.0, 0.0, 0.0, 1.0,
)
}
pub fn x(x: f32) -> Matrix4<f32> {
Translate::by(x, 0.0, 0.0)
}
pub fn y(y: f32) -> Matrix4<f32> {
Translate::by(0.0, y, 0.0)
}
pub fn z(z: f32) -> Matrix4<f32> {
Translate::by(0.0, 0.0, z)
}
}
#[derive(Default, Clone, Copy, Debug)]
struct Scale;
impl Scale {
pub fn all(factor: f32) -> Matrix4<f32> {
Scale::by(factor, factor, factor)
}
pub fn by(x: f32, y: f32, z: f32) -> Matrix4<f32> {
Matrix4::new(
x, 0.0, 0.0, 0.0, 0.0, y, 0.0, 0.0, 0.0, 0.0, z, 0.0, 0.0, 0.0, 0.0, 1.0,
)
}
}
#[derive(Clone, Copy, Debug)]
struct Rotate;
impl Rotate {
#[rustfmt::skip]
pub fn x(x: f32) -> Matrix4<f32> {
let r = x.to_radians();
Translate::by(0.0, 0.5, 0.5) * Matrix4::new(
1.0, 0.0, 0.0, 0.0, 0.0, r.cos(), -r.sin(), 0.0, 0.0, r.sin(), r.cos(), 0.0, 0.0, 0.0, 0.0, 1.0
) * Translate::by(0.0, -0.5, -0.5)
}
#[rustfmt::skip]
pub fn y(y: f32) -> Matrix4<f32> {
let r = y.to_radians();
Translate::by(0.5, 0.0, 0.5) * Matrix4::new(
r.cos(), 0.0, r.sin(), 0.0, 0.0, 1.0, 0.0, 0.0, -r.sin(), 0.0, r.cos(), 0.0, 0.0, 0.0, 0.0, 1.0
)* Translate::by(-0.5, 0.0, -0.5)
}
#[rustfmt::skip]
pub fn z(z: f32) -> Matrix4<f32> {
let r = z.to_radians();
Translate::by(0.5, 0.5, 0.0) * Matrix4::new(
r.cos(), -r.sin(), 0.0, 0.0, r.sin(), r.cos(), 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0
) * Translate::by(-0.5, -0.5, 0.0)
}
}