Skip to content

Commit 5b21ec7

Browse files
committed
Implement arithmetic operators for colors
Fixes #163.
1 parent 1c21ae6 commit 5b21ec7

File tree

4 files changed

+162
-36
lines changed

4 files changed

+162
-36
lines changed

core/src/math.rs

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,26 @@ pub use {
4040
mat::{orient_y, orient_z, rotate, rotate_x, rotate_y, rotate_z, rotate2},
4141
};
4242

43+
/// Implements an operator trait in terms of an op-assign trait.
44+
macro_rules! impl_op {
45+
($trait:ident :: $method:ident, $self:ident, $rhs:ty, $op:tt) => {
46+
impl_op!($trait::$method, $self, $rhs, $op, bound=Linear);
47+
};
48+
($trait:ident :: $method:ident, $self:ident, $rhs:ty, $op:tt, bound=$bnd:path) => {
49+
impl<R, Sp> $trait<$rhs> for $self<R, Sp>
50+
where
51+
Self: $bnd,
52+
{
53+
type Output = Self;
54+
/// TODO
55+
#[inline]
56+
fn $method(mut self, rhs: $rhs) -> Self {
57+
self $op rhs; self
58+
}
59+
}
60+
};
61+
}
62+
4363
pub mod angle;
4464
pub mod approx;
4565
pub mod color;

core/src/math/color.rs

Lines changed: 132 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,15 @@
11
//! Colors and color spaces.
22
3+
use core::ops::{
4+
Add, AddAssign, Div, DivAssign, Index, Mul, MulAssign, Neg, Sub, SubAssign,
5+
};
36
use core::{
47
array,
58
fmt::{self, Debug, Formatter},
69
marker::PhantomData,
7-
ops::Index,
810
};
911

10-
use crate::math::{Affine, Linear, Vector, float::f32, vary::ZDiv};
12+
use super::{Affine, Linear, Vector, vary::ZDiv};
1113

1214
//
1315
// Types
@@ -195,6 +197,7 @@ impl Color3f<Rgb> {
195197
#[cfg(feature = "fp")]
196198
#[inline]
197199
pub fn to_linear(self) -> Color3f<LinRgb> {
200+
use super::float::f32;
198201
self.0.map(|c| f32::powf(c, GAMMA)).into()
199202
}
200203

@@ -209,7 +212,7 @@ impl Color3f<Rgb> {
209212
let h = if d == 0.0 {
210213
0.0
211214
} else if max == r {
212-
f32::rem_euclid((g - b) / d, 6.0)
215+
super::float::f32::rem_euclid((g - b) / d, 6.0)
213216
} else if max == g {
214217
(b - r) / d + 2.0
215218
} else {
@@ -277,6 +280,7 @@ impl Color3f<LinRgb> {
277280
#[cfg(feature = "fp")]
278281
#[inline]
279282
pub fn to_srgb(self) -> Color3f<Rgb> {
283+
use super::float::f32;
280284
self.0.map(|c| f32::powf(c, INV_GAMMA)).into()
281285
}
282286
}
@@ -525,12 +529,102 @@ impl<R, Sp> From<R> for Color<R, Sp> {
525529
}
526530
}
527531

532+
//
533+
// Arithmetic trait impls
534+
//
535+
536+
//
537+
// Arithmetic traits
538+
//
539+
540+
/// The color += color operator.
541+
impl<R, D, Sp> AddAssign<D> for Color<R, Sp>
542+
where
543+
Self: Affine<Diff = D>,
544+
{
545+
#[inline]
546+
fn add_assign(&mut self, rhs: D) {
547+
*self = Affine::add(&*self, &rhs);
548+
}
549+
}
550+
551+
/// The color -= color operator.
552+
impl<R, D, Sp> SubAssign<D> for Color<R, Sp>
553+
where
554+
D: Linear,
555+
Self: Affine<Diff = D>,
556+
{
557+
#[inline]
558+
fn sub_assign(&mut self, rhs: D) {
559+
*self += rhs.neg();
560+
}
561+
}
562+
563+
// The color *= scalar operator.
564+
impl<R, Sc, Sp> MulAssign<Sc> for Color<R, Sp>
565+
where
566+
Self: Linear<Scalar = Sc>,
567+
{
568+
#[inline]
569+
fn mul_assign(&mut self, rhs: Sc) {
570+
*self = Linear::mul(&*self, rhs);
571+
}
572+
}
573+
574+
// The color /= scalar operator.
575+
impl<R, Sp> DivAssign<f32> for Color<R, Sp>
576+
where
577+
Self: Linear<Scalar = f32>,
578+
{
579+
#[inline]
580+
fn div_assign(&mut self, rhs: f32) {
581+
use crate::math::ApproxEq;
582+
debug_assert!(!rhs.approx_eq(&0.0));
583+
*self = Linear::mul(&*self, rhs.recip());
584+
}
585+
}
586+
587+
/// The color negation operator.
588+
impl<R, Sp> Neg for Color<R, Sp>
589+
where
590+
Self: Linear,
591+
{
592+
type Output = Self;
593+
594+
#[inline]
595+
fn neg(self) -> Self {
596+
<Self as Linear>::neg(&self)
597+
}
598+
}
599+
600+
/// The scalar * color operator.
601+
impl<R, Sp> Mul<Color<R, Sp>> for <Color<R, Sp> as Linear>::Scalar
602+
where
603+
Color<R, Sp>: Linear,
604+
{
605+
type Output = Color<R, Sp>;
606+
607+
#[inline]
608+
fn mul(self, rhs: Color<R, Sp>) -> Color<R, Sp> {
609+
rhs * self
610+
}
611+
}
612+
613+
// The color + color operator.
614+
impl_op!(Add::add, Color, <Self as Affine>::Diff, +=, bound=Affine);
615+
// The color - color operator.
616+
impl_op!(Sub::sub, Color, <Self as Affine>::Diff, -=, bound=Affine);
617+
// The color * scalar operator.
618+
impl_op!(Mul::mul, Color, <Self as Linear>::Scalar, *=);
619+
// The color / scalar operator.
620+
impl_op!(Div::div, Color, f32, /=, bound=Linear<Scalar = f32>);
621+
528622
#[cfg(test)]
529623
mod tests {
530624
use super::*;
531625

532626
#[test]
533-
fn color_components() {
627+
fn rgb_components() {
534628
assert_eq!(rgb(0xFF, 0, 0).r(), 0xFF);
535629
assert_eq!(rgb(0, 0xFF, 0).g(), 0xFF);
536630
assert_eq!(rgb(0, 0, 0xFF).b(), 0xFF);
@@ -541,6 +635,40 @@ mod tests {
541635
assert_eq!(rgba(0, 0, 0, 0xFF).a(), 0xFF);
542636
}
543637

638+
#[test]
639+
fn hsl_components() {
640+
assert_eq!(hsl(0xFF, 0, 0).h(), 0xFF);
641+
assert_eq!(hsl(0, 0xFF, 0).s(), 0xFF);
642+
assert_eq!(hsl(0, 0, 0xFF).l(), 0xFF);
643+
644+
assert_eq!(hsla(0xFF, 0, 0, 0).h(), 0xFF);
645+
assert_eq!(hsla(0, 0xFF, 0, 0).s(), 0xFF);
646+
assert_eq!(hsla(0, 0, 0xFF, 0).l(), 0xFF);
647+
assert_eq!(hsla(0, 0, 0, 0xFF).a(), 0xFF);
648+
}
649+
650+
#[test]
651+
fn rgb_f32_ops() {
652+
let lhs = rgb(0.5, 0.625, 0.75);
653+
let rhs = rgb(0.125, 0.25, 0.375);
654+
655+
assert_eq!(lhs + rhs, rgb(0.625, 0.875, 1.125));
656+
assert_eq!(lhs - rhs, rgb(0.375, 0.375, 0.375));
657+
assert_eq!(lhs * 0.5, rgb(0.25, 0.3125, 0.375));
658+
assert_eq!(0.5 * lhs, rgb(0.25, 0.3125, 0.375));
659+
assert_eq!(lhs / 2.0, rgb(0.25, 0.3125, 0.375));
660+
assert_eq!(-lhs, rgb(-0.5, -0.625, -0.75));
661+
}
662+
663+
#[test]
664+
fn rgb_u8_ops() {
665+
let lhs = rgb(0x77, 0x88, 0x99);
666+
let rhs = [0x11_i32, 0x33, 0x55].into();
667+
668+
assert_eq!(lhs + rhs, rgb(0x88, 0xBB, 0xEE));
669+
assert_eq!(lhs - rhs, rgb(0x66, 0x55, 0x44));
670+
}
671+
544672
#[test]
545673
fn rgb_to_hsl() {
546674
let cases = [

core/src/math/vec.rs

Lines changed: 9 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,6 @@ use core::{
1313

1414
use crate::math::{
1515
Affine, ApproxEq, Linear, Point,
16-
float::f32,
1716
space::{Proj3, Real},
1817
vary::ZDiv,
1918
};
@@ -604,26 +603,6 @@ where
604603
// Arithmetic traits
605604
//
606605

607-
/// Implements an operator trait in terms of an op-assign trait.
608-
macro_rules! impl_op {
609-
($trait:ident :: $method:ident, $rhs:ty, $op:tt) => {
610-
impl_op!($trait::$method, $rhs, $op, bound=Linear);
611-
};
612-
($trait:ident :: $method:ident, $rhs:ty, $op:tt, bound=$bnd:path) => {
613-
impl<R, Sp> $trait<$rhs> for Vector<R, Sp>
614-
where
615-
Self: $bnd,
616-
{
617-
type Output = Self;
618-
/// TODO docs for macro-generated operators
619-
#[inline]
620-
fn $method(mut self, rhs: $rhs) -> Self {
621-
self $op rhs; self
622-
}
623-
}
624-
};
625-
}
626-
627606
/// The vector += vector operator.
628607
impl<R, Sp> AddAssign<<Self as Affine>::Diff> for Vector<R, Sp>
629608
where
@@ -634,8 +613,6 @@ where
634613
*self = Affine::add(&*self, &rhs);
635614
}
636615
}
637-
// The vector + vector operator.
638-
impl_op!(Add::add, <Self as Affine>::Diff, +=, bound=Affine);
639616

640617
/// The vector -= vector operator.
641618
impl<R, Sp> SubAssign<<Self as Affine>::Diff> for Vector<R, Sp>
@@ -648,9 +625,6 @@ where
648625
}
649626
}
650627

651-
// The vector - vector operator.
652-
impl_op!(Sub::sub, <Self as Affine>::Diff, -=, bound=Affine);
653-
654628
// The vector *= scalar operator.
655629
impl<R, Sp> MulAssign<<Self as Linear>::Scalar> for Vector<R, Sp>
656630
where
@@ -661,8 +635,6 @@ where
661635
*self = Linear::mul(&*self, rhs);
662636
}
663637
}
664-
// The vector * scalar operator.
665-
impl_op!(Mul::mul, <Self as Linear>::Scalar, *=);
666638

667639
// The vector /= scalar operator.
668640
impl<R, Sp> DivAssign<f32> for Vector<R, Sp>
@@ -676,9 +648,6 @@ where
676648
}
677649
}
678650

679-
// The vector / scalar operator.
680-
impl_op!(Div::div, f32, /=, bound=Linear<Scalar = f32>);
681-
682651
/// The vector negation operator.
683652
impl<R, Sp> Neg for Vector<R, Sp>
684653
where
@@ -726,6 +695,15 @@ where
726695
}
727696
}
728697

698+
// The vector + vector operator.
699+
impl_op!(Add::add, Vector, <Self as Affine>::Diff, +=, bound=Affine);
700+
// The vector - vector operator.
701+
impl_op!(Sub::sub, Vector, <Self as Affine>::Diff, -=, bound=Affine);
702+
// The vector * scalar operator.
703+
impl_op!(Mul::mul, Vector, <Self as Linear>::Scalar, *=);
704+
// The vector / scalar operator.
705+
impl_op!(Div::div, Vector, f32, /=, bound=Linear<Scalar = f32>);
706+
729707
//
730708
// Unit tests
731709
//

demos/src/bin/solids.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -72,7 +72,7 @@ fn main() {
7272
let diffuse = (norm.z() + 0.2).max(0.2) * 0.8;
7373
// Visualize normal by mapping to RGB values
7474
let [r, g, b] = (0.45 * (v.attrib + splat(1.1))).0;
75-
let col = rgb(r, g, b).mul(diffuse);
75+
let col = diffuse * rgb(r, g, b);
7676
vertex(mvp.apply(&v.pos), col)
7777
}
7878

0 commit comments

Comments
 (0)