WIP: port libsquish c++ code to rust

This commit is contained in:
Jan Solanti
2018-08-23 17:14:09 +09:00
commit 3928496379
8 changed files with 1365 additions and 0 deletions
+4
View File
@@ -0,0 +1,4 @@
/target
**/*.rs.bk
Cargo.lock
.DS_Store
+6
View File
@@ -0,0 +1,6 @@
[package]
name = "squish-rs"
version = "0.1.0"
authors = ["Jan Solanti <jhs@psonet.com>"]
[dependencies]
+33
View File
@@ -0,0 +1,33 @@
// Copyright (c) 2006 Simon Brown <si@sjbrown.co.uk>
// Copyright (c) 2018 Jan Solanti <jhs@psonet.com>
//
// Permission is hereby granted, free of charge, to any person obtaining
// a copy of this software and associated documentation files (the
// "Software"), to deal in the Software without restriction, including
// without limitation the rights to use, copy, modify, merge, publish,
// distribute, sublicense, and/or sell copies of the Software, and to
// permit persons to whom the Software is furnished to do so, subject to
// the following conditions:
//
// The above copyright notice and this permission notice shall be included
// in all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
// IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
// CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
// SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
use math::Vec3;
use super::f32_to_i32_clamped;
fn vec3f_to_565(colour: Vec3) -> [u8; 2] {
let r = f32_to_i32_clamped(31.0*colour.x(), 31) as u8;
let g = f32_to_i32_clamped(63.0*colour.y(), 63) as u8;
let b = f32_to_i32_clamped(31.0*colour.z(), 31) as u8;
[ r << 3 | (g >> 3), (g << 5) | b]
}
+137
View File
@@ -0,0 +1,137 @@
// Copyright (c) 2006 Simon Brown <si@sjbrown.co.uk>
// Copyright (c) 2018 Jan Solanti <jhs@psonet.com>
//
// Permission is hereby granted, free of charge, to any person obtaining
// a copy of this software and associated documentation files (the
// "Software"), to deal in the Software without restriction, including
// without limitation the rights to use, copy, modify, merge, publish,
// distribute, sublicense, and/or sell copies of the Software, and to
// permit persons to whom the Software is furnished to do so, subject to
// the following conditions:
//
// The above copyright notice and this permission notice shall be included
// in all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
// IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
// CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
// SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
use ::Format;
use math::*;
pub struct ColourSet {
count: usize,
points: [Vec3; 16],
weights: [f32; 16],
remap: [i8; 16], // enough since there are only 16 possible indices
transparent: bool,
}
impl ColourSet {
pub fn new(rgba: &[[u8; 4]; 16], mask: u32, format: Format, alpha_weighted: bool) -> ColourSet {
let mut set = ColourSet {
count: 0,
points: [Vec3::new(0f32,0f32,0f32); 16],
weights: [0f32; 16],
remap: [0; 16],
transparent: false,
};
// create the minimal set
for i in 0..rgba.len() {
// skip this pixel if it's disabled
let bit = 1u32 << i;
if (mask & bit) == 0 {
set.remap[i] = -1;
continue;
}
// if using DXT1, skip transparent pixels
if (format == Format::Dxt1) && (rgba[i][3] < 128u8) {
set.remap[i] = -1;
set.transparent = true;
continue;
}
// loop over previous points in case the colour is duplicated in this block
for j in 0..rgba.len() {
// no duplicates found, store new point
if j == i {
// normalise coordinates to [0,1]
let x = rgba[i][0] as f32 / 255f32;
let y = rgba[i][1] as f32 / 255f32;
let z = rgba[i][2] as f32 / 255f32;
// ensure weight is always nonzero even when alpha is not
let w = (rgba[i][3] + 1) as f32 / 256f32;
// store point
set.points[set.count] = Vec3::new(x, y, z);
set.weights[set.count] = if alpha_weighted { w } else { 1f32 };
// move to next pixel
set.count += 1;
break;
}
// check for duplicates
let oldbit = 1u32 << j;
let duplicate = ((mask & oldbit) != 0)
&& ( rgba[i][0] == rgba[j][0] )
&& ( rgba[i][1] == rgba[j][1] )
&& ( rgba[i][2] == rgba[j][2] )
&& ( format != Format::Dxt1 || rgba[j][3] >= 128u8 );
if duplicate {
// get index of duplicate
let index = set.remap[j];
// ensure weight is always nonzero even when alpha is not
let w = (rgba[i][3] + 1) as f32 / 256f32;
// map this point to its duplicate and increase the duplicate's weight
set.weights[index as usize] += if alpha_weighted { w } else { 1f32 };
set.remap[i] = index;
// move to next pixel
break;
}
}
}
// square root the weights
for w in set.weights.iter_mut() {
*w = w.sqrt();
}
set
}
pub fn is_transparent(&self) -> bool {
self.transparent
}
pub fn points(&self) -> &[Vec3] {
&self.points[..self.count]
}
pub fn weights(&self) -> &[f32] {
&self.weights[..self.count]
}
pub fn remap_indices(&mut self, source: &[u8; 16], target: &mut [u8; 16]) {
for i in 0..source.len() {
let j = self.remap[i];
if j == -1 {
target[i] = 3;
} else {
target[i] = source[j as usize];
}
}
}
}
+243
View File
@@ -0,0 +1,243 @@
// Copyright (c) 2006 Simon Brown <si@sjbrown.co.uk>
// Copyright (c) 2018 Jan Solanti <jhs@psonet.com>
//
// Permission is hereby granted, free of charge, to any person obtaining
// a copy of this software and associated documentation files (the
// "Software"), to deal in the Software without restriction, including
// without limitation the rights to use, copy, modify, merge, publish,
// distribute, sublicense, and/or sell copies of the Software, and to
// permit persons to whom the Software is furnished to do so, subject to
// the following conditions:
//
// The above copyright notice and this permission notice shall be included
// in all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
// IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
// CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
// SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
//! A pure Rust DXT1/3/5 compressor and decompressor based on Simon Brown's
//! **libsquish**
mod math;
mod colourblock;
mod colourset;
/// Defines a compression format
#[derive(PartialEq, Eq)]
pub enum Format {
Dxt1,
Dxt3,
Dxt5,
}
/// Defines a compression algorithm
pub enum CompressionAlgorithm {
/// Fast, low quality
ColourRangeFit,
/// Slow, high quality (default)
ColourClusterFit,
/// Very slow, very high quality
ColourIterativeClusterFit,
}
/// A block of owned compressed data. Variants are for different block sizes
enum CompressedBlock {
Dxt1([u8; 8]),
Dxt3([u8; 8], [u8; 8]),
Dxt5([u8; 16]),
}
impl Default for CompressionAlgorithm {
fn default() -> Self { CompressionAlgorithm::ColourClusterFit }
}
/// RGB colour channel weights for use in block fitting
pub type ColourWeights = [f32; 3];
/// Weights based on the perceived brightness of each colour channel
pub const COLOUR_WEIGHTS_PERCEPTUAL: ColourWeights = [0.2126, 0.7152, 0.0722];
pub struct CompressorParams {
/// The compression algorithm to be used
pub algorithm: CompressionAlgorithm,
/// Weigh the relative importance of each colour channel when fitting
/// (defaults to equal weights)
pub weights: Option<ColourWeights>,
/// Weigh colour by alpha during cluster fit (defaults to false)
///
/// This can significantly increase perceived quality for images that are rendered
/// using alpha blending.
pub weigh_colour_by_alpha: bool,
}
impl Default for CompressorParams {
fn default() -> Self {
CompressorParams {
algorithm: CompressionAlgorithm::default(),
weights: None,
weigh_colour_by_alpha: false,
}
}
}
/// Decompresses an image in memory
///
/// * `data` - The compressed image data
/// * `width` - The width of the source image
/// * `height` - The height of the source image
/// * `format` - The compression format
pub fn decompress(
data: &[u8],
width: usize,
height: usize,
format: Format,
) -> Vec<u8> {
vec![]
}
/// Computes the amount of space in bytes needed for the compressed image
///
/// * `width` - Width of the uncompressed image
/// * `height` - Height of the uncompressed image
/// * `format` - The desired compression format
///
pub fn compute_compressed_size(
width: usize,
height: usize,
format: Format
) -> usize {
// Number of blocks required for image of given dimensions
let n_blocks = ((width + 3) / 4) * ((height + 3) / 4);
let blocksize = bytes_per_block(format);
n_blocks * blocksize
}
/// Compresses a 4x4 block of pixels
///
/// * `rgba` - The uncompressed block of pixels
/// * `format` - The desired compression format
/// * `params` - Additional compressor parameters
fn compress_block(
rgba: [[u8; 4]; 16],
format: Format,
params: Option<CompressorParams>
) -> () {
compress_block_masked(rgba, 0xffffffff, format, params)
}
/// Compresses a 4x4 block of pixels, masking out some pixels e.g. for padding the
/// image to a multiple of the block size.
///
/// * `rgba` - The uncompressed block of pixels
/// * `mask` - The valid pixel mask
/// * `format` - The desired compression format
/// * `params` - Additional compressor parameters
fn compress_block_masked(
rgba: [[u8; 4]; 16],
mask: u32,
format: Format,
params: Option<CompressorParams>
) -> () {
let params = params.unwrap_or(CompressorParams::default());
}
/// Decompresses a 4x4 block of pixels
///
/// * `rgba` - The compressed block of pixels
/// * `format` - The compression format of the data
fn decompress_block(
rgba: &CompressedBlock,
format: Format,
) -> () {
}
/// Compresses an image in memory
///
/// * `rgba` - The uncompressed pixel data
/// * `width` - The width of the source image
/// * `height` - The height of the source image
/// * `format` - The desired compression format
/// * `params` - Additional compressor parameters
pub fn compress(
rgba: &[u8],
width: usize,
height: usize,
format: Format,
params: Option<CompressorParams>
) -> Vec<u8> {
vec![]
}
/// Returns how many bytes a 4x4 block of pixels will take after compression,
/// given the compression format
fn bytes_per_block(format: Format) -> usize {
// Compressed block size in bytes
match format {
Format::Dxt1 => 8,
Format::Dxt3 => 16,
Format::Dxt5 => 16,
}
}
fn f32_to_i32_clamped(a: f32, limit: i32) -> i32 {
(a.round() as i32).max(0).min(limit)
}
//--------------------------------------------------------------------------------
// Unit tests
//--------------------------------------------------------------------------------
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_storage_requirements_dxt1_exact() {
let estimate = compute_compressed_size(16, 32, Format::Dxt1);
assert_eq!(estimate, 256);
}
#[test]
fn test_storage_requirements_dxt1_padded() {
let estimate = compute_compressed_size(15, 30, Format::Dxt1);
assert_eq!(estimate, 256);
}
#[test]
fn test_storage_requirements_dxt3_exact() {
let estimate = compute_compressed_size(16, 32, Format::Dxt3);
assert_eq!(estimate, 512);
}
#[test]
fn test_storage_requirements_dxt3_padded() {
let estimate = compute_compressed_size(15, 30, Format::Dxt3);
assert_eq!(estimate, 512);
}
#[test]
fn test_storage_requirements_dxt5_exact() {
let estimate = compute_compressed_size(16, 32, Format::Dxt5);
assert_eq!(estimate, 512);
}
#[test]
fn test_storage_requirements_dxt5_padded() {
let estimate = compute_compressed_size(15, 30, Format::Dxt5);
assert_eq!(estimate, 512);
}
}
+97
View File
@@ -0,0 +1,97 @@
// Copyright (c) 2006 Simon Brown <si@sjbrown.co.uk>
// Copyright (c) 2018 Jan Solanti <jhs@psonet.com>
//
// Permission is hereby granted, free of charge, to any person obtaining
// a copy of this software and associated documentation files (the
// "Software"), to deal in the Software without restriction, including
// without limitation the rights to use, copy, modify, merge, publish,
// distribute, sublicense, and/or sell copies of the Software, and to
// permit persons to whom the Software is furnished to do so, subject to
// the following conditions:
//
// The above copyright notice and this permission notice shall be included
// in all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
// IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
// CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
// SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
use std::f32;
mod vec3;
pub use self::vec3::*;
mod vec4;
pub use self::vec4::*;
/// A type representing a symmetric 3x3 matrix
pub struct Sym3x3 {
x: [f32; 6],
}
impl Sym3x3 {
fn new(s: f32) -> Self {
Self { x: [s, s, s, s, s, s] }
}
fn weighted_covariance(points: &[Vec3], weights: &[f32] ) -> Self {
assert!(points.len() == weights.len());
// compute the centroid
let total: f32 = weights.iter().sum();
let centroid: Vec3 = points.iter().zip(weights.iter())
.map(|(p, &w)| p*w).sum();
let centroid = if total > f32::EPSILON {
centroid / total
} else {
centroid
};
// accumulate the covariance matrix
let mut covariance = Sym3x3::new(0.0);
for (p, &w) in points.iter().zip(weights.iter()) {
let a: Vec3 = p - &centroid;
let b = &a * w;
covariance.x[..][0] += a.x()*b.x();
covariance.x[..][1] += a.x()*b.y();
covariance.x[..][2] += a.x()*b.z();
covariance.x[..][3] += a.y()*b.y();
covariance.x[..][4] += a.y()*b.z();
covariance.x[..][5] += a.z()*b.z();
}
covariance
}
fn principle_component(&self) -> Vec3 {
const POWER_ITERATION_COUNT: usize = 8;
let row0 = Vec4::new(self.x[0], self.x[1], self.x[2], 0.0);
let row1 = Vec4::new(self.x[0], self.x[1], self.x[2], 0.0);
let row2 = Vec4::new(self.x[0], self.x[1], self.x[2], 0.0);
let mut v = Vec4::new(1.0, 1.0, 1.0, 1.0);
for _ in 0..POWER_ITERATION_COUNT {
// matrix multiplication
let w = &row0 * v.splat_x();
let w = Vec4::multiply_add(&row1, &v.splat_y(), &w);
let w = Vec4::multiply_add(&row2, &v.splat_z(), &w);
// Construct Vec4 with max component from xyz in all channels
let a = w.x().max(w.y().max(w.z()));
let a = Vec4::new(a, a, a, a);
v = w * a.reciprocal();
}
v.to_vec3()
}
}
+428
View File
@@ -0,0 +1,428 @@
// Copyright (c) 2006 Simon Brown <si@sjbrown.co.uk>
// Copyright (c) 2018 Jan Solanti <jhs@psonet.com>
//
// Permission is hereby granted, free of charge, to any person obtaining
// a copy of this software and associated documentation files (the
// "Software"), to deal in the Software without restriction, including
// without limitation the rights to use, copy, modify, merge, publish,
// distribute, sublicense, and/or sell copies of the Software, and to
// permit persons to whom the Software is furnished to do so, subject to
// the following conditions:
//
// The above copyright notice and this permission notice shall be included
// in all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
// IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
// CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
// SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
use std::ops::{Add, AddAssign, Div, DivAssign, Mul, MulAssign, Sub, SubAssign};
use std::iter::Sum;
/// A 3-dimensional vector type
#[derive(Copy, Clone, PartialEq)]
pub struct Vec3 {
x: f32,
y: f32,
z: f32,
}
impl Vec3 {
pub fn new(x: f32, y: f32, z: f32) -> Self {
Self { x, y, z }
}
pub fn x(&self) -> f32 {
self.x
}
pub fn y(&self) -> f32 {
self.y
}
pub fn z(&self) -> f32 {
self.z
}
pub fn dot(&self, other: &Vec3) -> f32 {
self.x * other.x + self.y * other.y + self.z * other.z
}
pub fn length2(&self) -> f32 {
self.x * self.x + self.y * self.y + self.z * self.z
}
pub fn max(&self, other: Vec3) -> Vec3 {
Vec3::new(
self.x.max(other.x),
self.y.max(other.y),
self.z.max(other.z)
)
}
pub fn min(&self, other: Vec3) -> Vec3 {
Vec3::new(
self.x.min(other.x),
self.y.min(other.y),
self.z.min(other.z)
)
}
}
impl<'a> Add for &'a Vec3 {
type Output = Vec3;
fn add(self, other: &'a Vec3) -> Vec3 {
Vec3::new(
self.x + other.x,
self.y + other.y,
self.z + other.z
)
}
}
impl Add for Vec3 {
type Output = Vec3;
fn add(self, other: Vec3) -> Vec3 {
Vec3::new(
self.x + other.x,
self.y + other.y,
self.z + other.z
)
}
}
impl AddAssign<Vec3> for Vec3 {
fn add_assign(&mut self, other: Vec3) {
self.x += other.x;
self.y += other.y;
self.z += other.z;
}
}
impl<'a> Add<&'a Vec3> for Vec3 {
type Output = Vec3;
fn add(self, other: &'a Vec3) -> Vec3 {
Vec3::new(
self.x + other.x,
self.y + other.y,
self.z + other.z
)
}
}
impl<'a> AddAssign<&'a Vec3> for Vec3 {
fn add_assign(&mut self, other: &'a Vec3) {
self.x += other.x;
self.y += other.y;
self.z += other.z;
}
}
impl Add<f32> for Vec3 {
type Output = Vec3;
fn add(self, other: f32) -> Vec3 {
Vec3::new(
self.x + other,
self.y + other,
self.z + other
)
}
}
impl<'a> Add<f32> for &'a Vec3 {
type Output = Vec3;
fn add(self, other: f32) -> Vec3 {
Vec3::new(
self.x + other,
self.y + other,
self.z + other
)
}
}
impl AddAssign<f32> for Vec3 {
fn add_assign(&mut self, other: f32) {
self.x += other;
self.y += other;
self.z += other;
}
}
impl Sub for Vec3 {
type Output = Vec3;
fn sub(self, other: Vec3) -> Vec3 {
Vec3::new(
self.x - other.x,
self.y - other.y,
self.z - other.z
)
}
}
impl SubAssign<Vec3> for Vec3 {
fn sub_assign(&mut self, other: Vec3) {
self.x -= other.x;
self.y -= other.y;
self.z -= other.z;
}
}
impl<'a> Sub<&'a Vec3> for Vec3 {
type Output = Vec3;
fn sub(self, other: &'a Vec3) -> Vec3 {
Vec3::new(
self.x - other.x,
self.y - other.y,
self.z - other.z
)
}
}
impl<'a> Sub for &'a Vec3 {
type Output = Vec3;
fn sub(self, other: &'a Vec3) -> Vec3 {
Vec3::new(
self.x - other.x,
self.y - other.y,
self.z - other.z
)
}
}
impl<'a> SubAssign<&'a Vec3> for Vec3 {
fn sub_assign(&mut self, other: &'a Vec3) {
self.x -= other.x;
self.y -= other.y;
self.z -= other.z;
}
}
impl Sub<f32> for Vec3 {
type Output = Vec3;
fn sub(self, other: f32) -> Vec3 {
Vec3::new(
self.x - other,
self.y - other,
self.z - other
)
}
}
impl<'a> Sub<f32> for &'a Vec3 {
type Output = Vec3;
fn sub(self, other: f32) -> Vec3 {
Vec3::new(
self.x - other,
self.y - other,
self.z - other
)
}
}
impl SubAssign<f32> for Vec3 {
fn sub_assign(&mut self, other: f32) {
self.x -= other;
self.y -= other;
self.z -= other;
}
}
impl<'a> Mul for &'a Vec3 {
type Output = Vec3;
fn mul(self, other: &'a Vec3) -> Vec3 {
Vec3::new(
self.x * other.x,
self.y * other.y,
self.z * other.z
)
}
}
impl Mul for Vec3 {
type Output = Vec3;
fn mul(self, other: Vec3) -> Vec3 {
Vec3::new(
self.x * other.x,
self.y * other.y,
self.z * other.z
)
}
}
impl MulAssign for Vec3 {
fn mul_assign(&mut self, other: Vec3) {
self.x *= other.x;
self.y *= other.y;
self.z *= other.z;
}
}
impl<'a> Mul<&'a Vec3> for Vec3 {
type Output = Vec3;
fn mul(self, other: &'a Vec3) -> Vec3 {
Vec3::new(
self.x * other.x,
self.y * other.y,
self.z * other.z
)
}
}
impl<'a> MulAssign<&'a Vec3> for Vec3 {
fn mul_assign(&mut self, other: &'a Vec3) {
self.x *= other.x;
self.y *= other.y;
self.z *= other.z;
}
}
impl Mul<f32> for Vec3 {
type Output = Vec3;
fn mul(self, other: f32) -> Vec3 {
Vec3::new(
self.x * other,
self.y * other,
self.z * other
)
}
}
impl<'a> Mul<f32> for &'a Vec3 {
type Output = Vec3;
fn mul(self, other: f32) -> Vec3 {
Vec3::new(
self.x * other,
self.y * other,
self.z * other
)
}
}
impl MulAssign<f32> for Vec3 {
fn mul_assign(&mut self, other: f32) {
self.x *= other;
self.y *= other;
self.z *= other;
}
}
impl Div for Vec3 {
type Output = Vec3;
fn div(self, other: Vec3) -> Vec3 {
Vec3::new(
self.x / other.x,
self.y / other.y,
self.z / other.z
)
}
}
impl DivAssign for Vec3 {
fn div_assign(&mut self, other: Vec3) {
self.x /= other.x;
self.y /= other.y;
self.z /= other.z;
}
}
impl<'a> Div<&'a Vec3> for Vec3 {
type Output = Vec3;
fn div(self, other: &'a Vec3) -> Vec3 {
Vec3::new(
self.x / other.x,
self.y / other.y,
self.z / other.z
)
}
}
impl<'a> Div for &'a Vec3 {
type Output = Vec3;
fn div(self, other: &'a Vec3) -> Vec3 {
Vec3::new(
self.x / other.x,
self.y / other.y,
self.z / other.z
)
}
}
impl<'a> DivAssign<&'a Vec3> for Vec3 {
fn div_assign(&mut self, other: &'a Vec3) {
self.x /= other.x;
self.y /= other.y;
self.z /= other.z;
}
}
impl Div<f32> for Vec3 {
type Output = Vec3;
fn div(self, other: f32) -> Vec3 {
let t = 1.0 / other;
Vec3::new(
self.x * t,
self.y * t,
self.z * t
)
}
}
impl<'a> Div<f32> for &'a Vec3 {
type Output = Vec3;
fn div(self, other: f32) -> Vec3 {
let t = 1.0 / other;
Vec3::new(
self.x * t,
self.y * t,
self.z * t
)
}
}
impl DivAssign<f32> for Vec3 {
fn div_assign(&mut self, other: f32) {
let t = 1.0 / other;
self.x *= t;
self.y *= t;
self.z *= t;
}
}
impl Sum<Vec3> for Vec3 {
fn sum<I: Iterator<Item=Vec3>>(iter: I) -> Self {
iter.fold(Vec3::new(0.0, 0.0, 0.0), |a, b| a + b)
}
}
+417
View File
@@ -0,0 +1,417 @@
// Copyright (c) 2006 Simon Brown <si@sjbrown.co.uk>
// Copyright (c) 2018 Jan Solanti <jhs@psonet.com>
//
// Permission is hereby granted, free of charge, to any person obtaining
// a copy of this software and associated documentation files (the
// "Software"), to deal in the Software without restriction, including
// without limitation the rights to use, copy, modify, merge, publish,
// distribute, sublicense, and/or sell copies of the Software, and to
// permit persons to whom the Software is furnished to do so, subject to
// the following conditions:
//
// The above copyright notice and this permission notice shall be included
// in all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
// IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
// CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
// SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
use std::ops::{Add, AddAssign, Mul, MulAssign, Sub, SubAssign};
use super::Vec3;
pub struct Vec4 {
x: f32,
y: f32,
z: f32,
w: f32,
}
impl Vec4 {
pub fn new(x: f32, y: f32, z: f32, w: f32) -> Self {
Self { x, y, z, w }
}
pub fn x(&self) -> f32 {
self.x
}
pub fn y(&self) -> f32 {
self.y
}
pub fn z(&self) -> f32 {
self.z
}
pub fn w(&self) -> f32 {
self.w
}
pub fn to_vec3(&self) -> Vec3 {
Vec3::new(self.x, self.y, self.z)
}
pub fn splat_x(&self) -> Vec4 {
Vec4::new(self.x, self.x, self.x, self.x)
}
pub fn splat_y(&self) -> Vec4 {
Vec4::new(self.y, self.y, self.y, self.y)
}
pub fn splat_z(&self) -> Vec4 {
Vec4::new(self.z, self.z, self.z, self.z)
}
pub fn splat_w(&self) -> Vec4 {
Vec4::new(self.w, self.w, self.w, self.w)
}
pub fn reciprocal(&self) -> Vec4 {
Vec4::new(1.0/self.x, 1.0/self.y, 1.0/self.z, 1.0/self.w)
}
pub fn any_less_than(&self, other: &Vec4) -> bool {
self.x < other.x || self.y < other.y || self.z < other.z || self.w < other.w
}
pub fn truncate(&self) -> Vec4 {
Vec4::new(self.x.trunc(), self.y.trunc(), self.z.trunc(), self.w.trunc())
}
pub fn multiply_add<'a>(a: &'a Vec4, b: &'a Vec4, c: &'a Vec4) -> Vec4 {
a * b + c
}
pub fn negative_multiply_subtract<'a>(a: &'a Vec4, b: &'a Vec4, c: &'a Vec4) -> Vec4 {
c - a * b
}
}
impl Add for Vec4 {
type Output = Vec4;
fn add(self, other: Vec4) -> Vec4 {
Vec4::new(
self.x + other.x,
self.y + other.y,
self.z + other.z,
self.w + other.w
)
}
}
impl<'a> Add for &'a Vec4 {
type Output = Vec4;
fn add(self, other: &'a Vec4) -> Vec4 {
Vec4::new(
self.x + other.x,
self.y + other.y,
self.z + other.z,
self.w + other.w
)
}
}
impl<'a> Add<Vec4> for &'a Vec4 {
type Output = Vec4;
fn add(self, other: Vec4) -> Vec4 {
Vec4::new(
self.x + other.x,
self.y + other.y,
self.z + other.z,
self.w + other.w
)
}
}
impl<'a> Add<&'a Vec4> for Vec4 {
type Output = Vec4;
fn add(self, other: &'a Vec4) -> Vec4 {
Vec4::new(
self.x + other.x,
self.y + other.y,
self.z + other.z,
self.w + other.w
)
}
}
impl Add<f32> for Vec4 {
type Output = Vec4;
fn add(self, other: f32) -> Vec4 {
Vec4::new(
self.x + other,
self.y + other,
self.z + other,
self.w + other
)
}
}
impl<'a> Add<f32> for &'a Vec4 {
type Output = Vec4;
fn add(self, other: f32) -> Vec4 {
Vec4::new(
self.x + other,
self.y + other,
self.z + other,
self.w + other
)
}
}
impl AddAssign<Vec4> for Vec4 {
fn add_assign(&mut self, other: Vec4) {
self.x += other.x;
self.y += other.y;
self.z += other.z;
self.w += other.w;
}
}
impl<'a> AddAssign<&'a Vec4> for Vec4 {
fn add_assign(&mut self, other: &'a Vec4) {
self.x += other.x;
self.y += other.y;
self.z += other.z;
self.w += other.w;
}
}
impl AddAssign<f32> for Vec4 {
fn add_assign(&mut self, other: f32) {
self.x += other;
self.y += other;
self.z += other;
self.w += other;
}
}
impl Sub for Vec4 {
type Output = Vec4;
fn sub(self, other: Vec4) -> Vec4 {
Vec4::new(
self.x - other.x,
self.y - other.y,
self.z - other.z,
self.w - other.w
)
}
}
impl<'a> Sub for &'a Vec4 {
type Output = Vec4;
fn sub(self, other: &'a Vec4) -> Vec4 {
Vec4::new(
self.x - other.x,
self.y - other.y,
self.z - other.z,
self.w - other.w
)
}
}
impl<'a> Sub<Vec4> for &'a Vec4 {
type Output = Vec4;
fn sub(self, other: Vec4) -> Vec4 {
Vec4::new(
self.x - other.x,
self.y - other.y,
self.z - other.z,
self.w - other.w
)
}
}
impl<'a> Sub<&'a Vec4> for Vec4 {
type Output = Vec4;
fn sub(self, other: &'a Vec4) -> Vec4 {
Vec4::new(
self.x - other.x,
self.y - other.y,
self.z - other.z,
self.w - other.w
)
}
}
impl Sub<f32> for Vec4 {
type Output = Vec4;
fn sub(self, other: f32) -> Vec4 {
Vec4::new(
self.x - other,
self.y - other,
self.z - other,
self.w - other
)
}
}
impl<'a> Sub<f32> for &'a Vec4 {
type Output = Vec4;
fn sub(self, other: f32) -> Vec4 {
Vec4::new(
self.x - other,
self.y - other,
self.z - other,
self.w - other
)
}
}
impl SubAssign<Vec4> for Vec4 {
fn sub_assign(&mut self, other: Vec4) {
self.x -= other.x;
self.y -= other.y;
self.z -= other.z;
self.w -= other.w;
}
}
impl<'a> SubAssign<&'a Vec4> for Vec4 {
fn sub_assign(&mut self, other: &'a Vec4) {
self.x -= other.x;
self.y -= other.y;
self.z -= other.z;
self.w -= other.w;
}
}
impl SubAssign<f32> for Vec4 {
fn sub_assign(&mut self, other: f32) {
self.x -= other;
self.y -= other;
self.z -= other;
self.w -= other;
}
}
impl Mul for Vec4 {
type Output = Vec4;
fn mul(self, other: Vec4) -> Vec4 {
Vec4::new(
self.x * other.x,
self.y * other.y,
self.z * other.z,
self.w * other.w
)
}
}
impl<'a> Mul for &'a Vec4 {
type Output = Vec4;
fn mul(self, other: &'a Vec4) -> Vec4 {
Vec4::new(
self.x * other.x,
self.y * other.y,
self.z * other.z,
self.w * other.w
)
}
}
impl<'a> Mul<Vec4> for &'a Vec4 {
type Output = Vec4;
fn mul(self, other: Vec4) -> Vec4 {
Vec4::new(
self.x * other.x,
self.y * other.y,
self.z * other.z,
self.w * other.w
)
}
}
impl<'a> Mul<&'a Vec4> for Vec4 {
type Output = Vec4;
fn mul(self, other: &'a Vec4) -> Vec4 {
Vec4::new(
self.x * other.x,
self.y * other.y,
self.z * other.z,
self.w * other.w
)
}
}
impl Mul<f32> for Vec4 {
type Output = Vec4;
fn mul(self, other: f32) -> Vec4 {
Vec4::new(
self.x * other,
self.y * other,
self.z * other,
self.w * other
)
}
}
impl<'a> Mul<f32> for &'a Vec4 {
type Output = Vec4;
fn mul(self, other: f32) -> Vec4 {
Vec4::new(
self.x * other,
self.y * other,
self.z * other,
self.w * other
)
}
}
impl MulAssign<Vec4> for Vec4 {
fn mul_assign(&mut self, other: Vec4) {
self.x *= other.x;
self.y *= other.y;
self.z *= other.z;
self.w *= other.w;
}
}
impl<'a> MulAssign<&'a Vec4> for Vec4 {
fn mul_assign(&mut self, other: &'a Vec4) {
self.x *= other.x;
self.y *= other.y;
self.z *= other.z;
self.w *= other.w;
}
}
impl MulAssign<f32> for Vec4 {
fn mul_assign(&mut self, other: f32) {
self.x *= other;
self.y *= other;
self.z *= other;
self.w *= other;
}
}