mirror of
https://github.com/encounter/squish-rs.git
synced 2026-07-11 06:18:39 -07:00
WIP: port libsquish c++ code to rust
This commit is contained in:
@@ -0,0 +1,4 @@
|
||||
/target
|
||||
**/*.rs.bk
|
||||
Cargo.lock
|
||||
.DS_Store
|
||||
@@ -0,0 +1,6 @@
|
||||
[package]
|
||||
name = "squish-rs"
|
||||
version = "0.1.0"
|
||||
authors = ["Jan Solanti <jhs@psonet.com>"]
|
||||
|
||||
[dependencies]
|
||||
@@ -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]
|
||||
}
|
||||
@@ -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
@@ -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);
|
||||
}
|
||||
}
|
||||
@@ -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 - ¢roid;
|
||||
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()
|
||||
}
|
||||
}
|
||||
@@ -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)
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user