# gfxmath-vec4
A simple 3D math library to compute 3 dimensional vectors.

- [Usage](#usage)
    * [Vec4](#vec4)
    * [Operators](#operators)
        - [Cross Product](#cross-product)
        - [Dot Product](#dot-product)
        - [Normalize](#normalize)
- [Known Limitations](#known-limitations)
    * [Left-Hand Primitives](#left-hand-primitives)
    * [Hash Implementation](#hash-implementation)
- [License](#license)

# Usage

## Vec4
Vec4 uses the `{ x, y, z }` coordinate system, with the trailing `w`. We can obtain the coefficients
for each axis by calling its member. 

The structure of Vec4 is as follows:

```rust
pub struct Vec4<T> {
    pub x: T,
    pub y: T,
    pub z: T,
    pub w: T
}
```

Depending on the context, Vec4 could be used to represent different types of data.
In graphics computing, it is common to use Vec4 to represent both point space and 
vectors, using the `w` to distinguish the two.

For example, a `w` that equals to `0.0` would be considered as a vector while a 
non-zero value would be considered a point in 3D space. Other times, the `w` could
be used to represent the scaling factor of the vector or point.

In the case for colors, we could use `{ x, y, z, w }` to represent
(red, green, blue, alpha).

The creation of a Vec4 objection can be done via multiple ways.

```rust
use gfxmath_vec4::Vec4;

// Standard construction
let v = Vec4 { x: 3.0, y: 1.0, z: 0.5, w: 4.2 };

// Using `new` function
let v = Vec4::new(3.0, 1.0, 0.5, 4.2);

// Using tuples
let v: Vec4<f32> = (3.0, 4.0, 9.0, 4.2).into();

// Using macros
use gfxmath_vec4::vec4;
let v = vec4!(3.0, 4.0, 9.0, 4.2);

assert_eq!(3.0, v.x);
assert_eq!(1.0, v.y);
assert_eq!(0.5, v.z);
assert_eq!(4.2, v.w);
```

## Operators
Common mathematical operators are implemented for Vec3.

* `+` , `+=`
* `-` , `-=`
* `*` , `*=`
* `/` , `/=`

```rust
// Reminder: Rust automatically infers floats to `f64` and integers to `i64`.

let v1 = Vec4::new(3.0, 9.0, 2.5, 1.0);
let v2 = Vec4::new(4.0, 5.0, 3.0, 0.0);

let res = v1 + v2;

assert_eq!( 7.0, res.x);
assert_eq!(14.0, res.y);
assert_eq!( 5.5, res.z);
assert_eq!( 1.0, res.w);
```

### Cross Product
The cross product returns a 3D vector with a zero `w` value.

```rust
use gfxmath_vec4::ops::Cross;
use gfxmath_vec4::Vec4;

let a = Vec4::new(1.0, 3.0, 2.5, 9.0);
let b = Vec4::all(2.0);

let res = a.cross(b);

assert_eq!( 1.0, res.x);
assert_eq!( 3.0, res.y);
assert_eq!(-4.0, res.z);
assert_eq!( 0.0, res.w);
```

### Dot Product
The dot product of Vec4 only computes the dot product of the (x, y, z) component
of the vector.

```rust
use gfxmath_vec4::{Vec4, ops::Dot};
 
let a = Vec4::new(3.0, 4.0, 5.0, 3.0);
let b = Vec4::new(2.0, 1.0, 3.0, 9.0);
 
let res = a.dot(b);
 
assert_eq!(25.0, res);
```

### Normalize
We can use `norm` from `gfxmath_vec4::ops::Norm` to normalize the vector.

This may be subject to change in the future due to `norm` being a word used 
to represent the length of the vector. `Norm` was selected for compactness so it
may be confusing for some people.

```rust
use gfxmath_vec4::ops::Norm;
use gfxmath_vec4::Vec4;

let a = Vec4::<f32>::new(3.0, 4.0, 0.0, 0.0);
let an = a.norm().unwrap();

assert_eq!(3.0/5.0, an.x);
assert_eq!(4.0/5.0, an.y);
assert_eq!(0.0, an.z);
assert_eq!(0.0, an.w); // this should always be zero so that this object is represented as a vector
```

# Known Limitations

## Left-Hand Primitives
One caveat is that operators where the Left-Hand side is a primitive has limited support. This is due to restrictions for trait implementations. `impl <T> Add<Vec3<T>> for T` is illegal within Rust syntax (due to the trailing `T`) because the implementation must be for a known type for non-local traits and types. Since `Add` is from the `core` package and `T` (the type to be implemented for) is not derived from a local trait, this is not possible.

At the time of this writing, primitives that work on the Left-Hand Side for common operators are `f32`, `f64`, `i32`, and `i64`.

```rust
// Works
let lhs: f32 = 4.0;
let rhs = Vec4::<f32>::new(3.0, 4.0, 2.5, 3.0);
let res = lhs + rhs;

// NOT SUPPORTED!!
let lhs: u32 = 4;
let rhs = Vec4::<u32>::new(3, 4, 2, 3);
let res = lhs + rhs;
```

## Hash Implementation
Currently, Hash implementations are limited for the following types:
- `f32`
- `f64`
- `i32`
- `i64`
- `u32`
- `u64`
