diff --git a/README.md b/README.md
index fadbea4..5a4c076 100644
--- a/README.md
+++ b/README.md
@@ -1,10 +1,44 @@
+
+
# VMath
`nimble install vmath`
-Collection of math routines for 2d and 3d graphics.
+Your single stop for vector math routines for 2d and 3d graphics.
-Has functions for Vec2, Vec3, Vec4, Mat3, Mat4 and Quat.
+Pure nim no dependencies. Fast. Easy to use.
+
+## Has functions for:
+
+Type | Constructor | Description
+------|-------------| ---------------------------------------------------
+BVec# | bvec# | a vector of booleans
+IVec# | ivec# | a vector of signed integers
+UVec# | uvec# | a vector of unsigned integers
+Vec# | vec# | a vector of single-precision floating-point numbers
+DVec# | dvec# | a vector of double-precision floating-point numbers
+
+## And these types:
+
+NIM | GLSL | 2 | 3 | 4 | 9 | 16 | 4 |
+--------|--------|-------|-------|-------|-------|-------|-------|
+bool | bool | BVec2 | BVec3 | BVec4 | | | |
+int32 | int | IVec2 | IVec3 | IVec4 | | | |
+uint32 | uint | UVec2 | UVec3 | UVec4 | | | |
+float32 | float | Vec2 | Vec3 | Vec4 | Mat3 | Mat4 | Quat |
+float64 | double | DVec2 | DVec3 | DVec4 | DMat3 | DMat4 | DQuat |
+
+
+# 0.x.x to 1.0.0 vmath breaking changes:
+
+* `vec3(v)` no longer works please use `vec3(v.x, v.y, 0)` instead.
+* `vec3(v, 0)` no longer works please use `vec3(v.x, v.y, 0)` instead.
+* `2 * v` no longer works due to more vec types please use `v * 2` instead.
+* `m[15]` no longer works because matrices are now m[x, y].
+* Concept of 3x3 rotation 3d matrix was removed.
+* `angleBetween` got renamed to `angle(a, b)`
+* `scaleMat` got renamed to `scale(v)`
+* `rotationMat3` got renamed to `rotate(x)`
# API: vmath
@@ -12,12 +46,138 @@ Has functions for Vec2, Vec3, Vec4, Mat3, Mat4 and Quat.
import vmath
```
+## **type** GVec2
+
+
+```nim
+GVec2[T] = array[2, T]
+```
+
+## **type** GVec3
+
+
+```nim
+GVec3[T] = array[3, T]
+```
+
+## **type** GVec4
+
+
+```nim
+GVec4[T] = array[4, T]
+```
+
+## **type** BVec2
+
+
+```nim
+BVec2 = GVec2[bool]
+```
+
+## **type** BVec3
+
+
+```nim
+BVec3 = GVec3[bool]
+```
+
+## **type** BVec4
+
+
+```nim
+BVec4 = GVec4[bool]
+```
+
+## **type** IVec2
+
+
+```nim
+IVec2 = GVec2[int32]
+```
+
+## **type** IVec3
+
+
+```nim
+IVec3 = GVec3[int32]
+```
+
+## **type** IVec4
+
+
+```nim
+IVec4 = GVec4[int32]
+```
+
+## **type** UVec2
+
+
+```nim
+UVec2 = GVec2[uint32]
+```
+
+## **type** UVec3
+
+
+```nim
+UVec3 = GVec3[uint32]
+```
+
+## **type** UVec4
+
+
+```nim
+UVec4 = GVec4[uint32]
+```
+
+## **type** Vec2
+
+
+```nim
+Vec2 = GVec2[float32]
+```
+
+## **type** Vec3
+
+
+```nim
+Vec3 = GVec3[float32]
+```
+
+## **type** Vec4
+
+
+```nim
+Vec4 = GVec4[float32]
+```
+
+## **type** DVec2
+
+
+```nim
+DVec2 = GVec2[float64]
+```
+
+## **type** DVec3
+
+
+```nim
+DVec3 = GVec3[float64]
+```
+
+## **type** DVec4
+
+
+```nim
+DVec4 = GVec4[float64]
+```
+
## **proc** `~=`
Almost equal.
```nim
-proc `~=`(a, b: float32): bool
+proc `~=`[T: SomeFloat](a, b: T): bool {.inline.}
```
## **proc** between
@@ -25,7 +185,7 @@ proc `~=`(a, b: float32): bool
Returns true if value is between min and max or equal to them.
```nim
-proc between(value, min, max: float32): bool {.inline.}
+proc between[T](value, min, max: T): bool {.inline.}
```
## **proc** sign
@@ -33,15 +193,15 @@ proc between(value, min, max: float32): bool {.inline.}
Returns the sign of a number, -1 or 1.
```nim
-proc sign(v: float32): float32 {.inline.}
+proc sign[T](v: T): T {.inline.}
```
## **proc** quantize
-Makes v be multipe of n. Rounding to integer quantize by 1.0.
+Makes v be multiple of n. Rounding to integer quantize by 1.0.
```nim
-proc quantize(v, n: float32): float32 {.inline.}
+proc quantize[T: SomeFloat](v, n: T): T {.inline.}
```
## **proc** lerp
@@ -52,7 +212,7 @@ Interpolates value between a and b.
* 0.5 -> between a and b
```nim
-proc lerp(a, b, v: float32): float32 {.inline.}
+proc lerp[T: SomeFloat](a, b, v: T): T {.inline.}
```
## **proc** fixAngle
@@ -60,7 +220,7 @@ proc lerp(a, b, v: float32): float32 {.inline.}
Make angle be from -PI to PI radians.
```nim
-proc fixAngle(angle: float32): float32
+proc fixAngle[T: SomeFloat](angle: T): T {.inline.}
```
## **proc** angleBetween
@@ -68,7 +228,7 @@ proc fixAngle(angle: float32): float32
Angle between angle a and angle b.
```nim
-proc angleBetween(a, b: float32): float32 {.inline.}
+proc angleBetween[T: SomeFloat](a, b: T): T {.inline.}
```
## **proc** turnAngle
@@ -76,1052 +236,2054 @@ proc angleBetween(a, b: float32): float32 {.inline.}
Move from angle a to angle b with step of v.
```nim
-proc turnAngle(a, b, speed: float32): float32
+proc turnAngle[T: SomeFloat](a, b, speed: T): T {.inline.}
```
-## **type** Vec2
+## **proc** toRadians
-2D vector
```nim
-Vec2 = object
- x*: float32
- y*: float32
+proc toRadians[T: SomeFloat](deg: T): T {.inline.}
+```
+
+## **proc** toDegrees
+
+
+```nim
+proc toDegrees[T: SomeFloat](rad: T): T {.inline.}
+```
+
+## **proc** gvec2
+
+
+```nim
+proc gvec2[T](x, y: T): GVec2[T] {.inline.}
+```
+
+## **proc** gvec3
+
+
+```nim
+proc gvec3[T](x, y, z: T): GVec3[T] {.inline.}
+```
+
+## **proc** gvec4
+
+
+```nim
+proc gvec4[T](x, y, z, w: T): GVec4[T] {.inline.}
+```
+
+## **proc** bvec2
+
+
+```nim
+proc bvec2(x`gensym4, y`gensym4: bool): BVec2 {.inline.}
+```
+
+## **proc** bvec3
+
+
+```nim
+proc bvec3(x`gensym4, y`gensym4, z`gensym4: bool): BVec3 {.inline, tags: [].}
+```
+
+## **proc** bvec4
+
+
+```nim
+proc bvec4(x`gensym4, y`gensym4, z`gensym4, w`gensym4: bool): BVec4 {.inline, raises: [].}
+```
+
+## **proc** bvec2
+
+
+```nim
+proc bvec2(x`gensym4: bool): BVec2 {.inline.}
+```
+
+## **proc** bvec3
+
+
+```nim
+proc bvec3(x`gensym4: bool): BVec3 {.inline.}
+```
+
+## **proc** bvec4
+
+
+```nim
+proc bvec4(x`gensym4: bool): BVec4 {.inline.}
+```
+
+## **proc** bvec2
+
+
+```nim
+proc bvec2[T](x`gensym4: GVec2[T]): BVec2 {.inline.}
+```
+
+## **proc** bvec3
+
+
+```nim
+proc bvec3[T](x`gensym4: GVec3[T]): BVec3 {.inline.}
+```
+
+## **proc** bvec4
+
+
+```nim
+proc bvec4[T](x`gensym4: GVec4[T]): BVec4 {.inline.}
+```
+
+## **proc** bvec3
+
+
+```nim
+proc bvec3[T](x`gensym4: GVec2[T]): BVec3 {.inline.}
+```
+
+## **proc** bvec4
+
+
+```nim
+proc bvec4[T](x`gensym4: GVec3[T]): BVec4 {.inline.}
+```
+
+## **proc** ivec2
+
+
+```nim
+proc ivec2(x`gensym5, y`gensym5: int32): IVec2 {.inline.}
+```
+
+## **proc** ivec3
+
+
+```nim
+proc ivec3(x`gensym5, y`gensym5, z`gensym5: int32): IVec3 {.inline, tags: [].}
+```
+
+## **proc** ivec4
+
+
+```nim
+proc ivec4(x`gensym5, y`gensym5, z`gensym5, w`gensym5: int32): IVec4 {.inline, raises: [].}
+```
+
+## **proc** ivec2
+
+
+```nim
+proc ivec2(x`gensym5: int32): IVec2 {.inline.}
+```
+
+## **proc** ivec3
+
+
+```nim
+proc ivec3(x`gensym5: int32): IVec3 {.inline.}
+```
+
+## **proc** ivec4
+
+
+```nim
+proc ivec4(x`gensym5: int32): IVec4 {.inline.}
+```
+
+## **proc** ivec2
+
+
+```nim
+proc ivec2[T](x`gensym5: GVec2[T]): IVec2 {.inline.}
+```
+
+## **proc** ivec3
+
+
+```nim
+proc ivec3[T](x`gensym5: GVec3[T]): IVec3 {.inline.}
+```
+
+## **proc** ivec4
+
+
+```nim
+proc ivec4[T](x`gensym5: GVec4[T]): IVec4 {.inline.}
+```
+
+## **proc** ivec3
+
+
+```nim
+proc ivec3[T](x`gensym5: GVec2[T]): IVec3 {.inline.}
+```
+
+## **proc** ivec4
+
+
+```nim
+proc ivec4[T](x`gensym5: GVec3[T]): IVec4 {.inline.}
+```
+
+## **proc** uvec2
+
+
+```nim
+proc uvec2(x`gensym6, y`gensym6: uint32): UVec2 {.inline.}
+```
+
+## **proc** uvec3
+
+
+```nim
+proc uvec3(x`gensym6, y`gensym6, z`gensym6: uint32): UVec3 {.inline, tags: [].}
+```
+
+## **proc** uvec4
+
+
+```nim
+proc uvec4(x`gensym6, y`gensym6, z`gensym6, w`gensym6: uint32): UVec4 {.inline, raises: [].}
+```
+
+## **proc** uvec2
+
+
+```nim
+proc uvec2(x`gensym6: uint32): UVec2 {.inline.}
+```
+
+## **proc** uvec3
+
+
+```nim
+proc uvec3(x`gensym6: uint32): UVec3 {.inline.}
+```
+
+## **proc** uvec4
+
+
+```nim
+proc uvec4(x`gensym6: uint32): UVec4 {.inline.}
+```
+
+## **proc** uvec2
+
+
+```nim
+proc uvec2[T](x`gensym6: GVec2[T]): UVec2 {.inline.}
+```
+
+## **proc** uvec3
+
+
+```nim
+proc uvec3[T](x`gensym6: GVec3[T]): UVec3 {.inline.}
+```
+
+## **proc** uvec4
+
+
+```nim
+proc uvec4[T](x`gensym6: GVec4[T]): UVec4 {.inline.}
+```
+
+## **proc** uvec3
+
+
+```nim
+proc uvec3[T](x`gensym6: GVec2[T]): UVec3 {.inline.}
+```
+
+## **proc** uvec4
+
+
+```nim
+proc uvec4[T](x`gensym6: GVec3[T]): UVec4 {.inline.}
```
## **proc** vec2
```nim
-proc vec2(x, y: float32): Vec2 {.inline.}
+proc vec2(x`gensym7, y`gensym7: float32): Vec2 {.inline.}
+```
+
+## **proc** vec3
+
+
+```nim
+proc vec3(x`gensym7, y`gensym7, z`gensym7: float32): Vec3 {.inline, tags: [].}
+```
+
+## **proc** vec4
+
+
+```nim
+proc vec4(x`gensym7, y`gensym7, z`gensym7, w`gensym7: float32): Vec4 {.inline, raises: [].}
```
## **proc** vec2
```nim
-proc vec2(v: float32): Vec2 {.inline.}
+proc vec2(x`gensym7: float32): Vec2 {.inline.}
+```
+
+## **proc** vec3
+
+
+```nim
+proc vec3(x`gensym7: float32): Vec3 {.inline.}
+```
+
+## **proc** vec4
+
+
+```nim
+proc vec4(x`gensym7: float32): Vec4 {.inline.}
```
## **proc** vec2
```nim
-proc vec2(a: Vec2): Vec2 {.inline.}
-```
-
-## **proc** `~=`
-
-
-```nim
-proc `~=`(a, b: Vec2): bool
-```
-
-## **proc** `+`
-
-
-```nim
-proc `+`(a, b: Vec2): Vec2 {.inline.}
-```
-
-## **proc** `-`
-
-
-```nim
-proc `-`(a, b: Vec2): Vec2 {.inline.}
-```
-
-## **proc** `*`
-
-
-```nim
-proc `*`(a: Vec2; b: float32): Vec2 {.inline.}
-```
-
-## **proc** `*`
-
-
-```nim
-proc `*`(a: float32; b: Vec2): Vec2 {.inline.}
-```
-
-## **proc** `/`
-
-
-```nim
-proc `/`(a: Vec2; b: float32): Vec2 {.inline.}
-```
-
-## **proc** `+=`
-
-
-```nim
-proc `+=`(a: var Vec2; b: Vec2) {.inline.}
-```
-
-## **proc** `-=`
-
-
-```nim
-proc `-=`(a: var Vec2; b: Vec2) {.inline.}
-```
-
-## **proc** `*=`
-
-
-```nim
-proc `*=`(a: var Vec2; b: float32) {.inline.}
-```
-
-## **proc** `/=`
-
-
-```nim
-proc `/=`(a: var Vec2; b: float32) {.inline.}
-```
-
-## **proc** zero
-
-
-```nim
-proc zero(a: var Vec2) {.inline.}
-```
-
-## **proc** `-`
-
-
-```nim
-proc `-`(a: Vec2): Vec2 {.inline.}
-```
-
-## **proc** hash
-
-
-```nim
-proc hash(a: Vec2): Hash {.inline.}
-```
-
-## **proc** lengthSq
-
-
-```nim
-proc lengthSq(a: Vec2): float32 {.inline.}
-```
-
-## **proc** length
-
-
-```nim
-proc length(a: Vec2): float32 {.inline.}
-```
-
-## **proc** length=
-
-
-```nim
-proc length=(a: var Vec2; b: float32) {.inline.}
-```
-
-## **proc** normalize
-
-
-```nim
-proc normalize(a: Vec2): Vec2 {.inline.}
-```
-
-## **proc** floor
-
-
-```nim
-proc floor(a: Vec2): Vec2 {.inline.}
-```
-
-## **proc** round
-
-
-```nim
-proc round(a: Vec2): Vec2 {.inline.}
-```
-
-## **proc** ceil
-
-
-```nim
-proc ceil(a: Vec2): Vec2 {.inline.}
-```
-
-## **proc** dot
-
-
-```nim
-proc dot(a, b: Vec2): float32 {.inline.}
-```
-
-## **proc** dir
-
-
-```nim
-proc dir(at, to: Vec2): Vec2 {.inline.}
-```
-
-## **proc** dir
-
-
-```nim
-proc dir(th: float32): Vec2 {.inline.}
-```
-
-## **proc** dist
-
-
-```nim
-proc dist(at, to: Vec2): float32 {.inline.}
-```
-
-## **proc** distSq
-
-
-```nim
-proc distSq(at, to: Vec2): float32 {.inline.}
-```
-
-## **proc** lerp
-
-
-```nim
-proc lerp(a, b: Vec2; v: float32): Vec2 {.inline.}
-```
-
-## **proc** quantize
-
-
-```nim
-proc quantize(v: Vec2; n: float32): Vec2 {.inline.}
-```
-
-## **proc** `[]`
-
-
-```nim
-proc `[]`(a: Vec2; i: int): float32
-```
-
-## **proc** `[]=`
-
-
-```nim
-proc `[]=`(a: var Vec2; i: int; b: float32)
-```
-
-## **proc** randVec2
-
-
-```nim
-proc randVec2(r: var Rand): Vec2
-```
-
-## **proc** `$`
-
-
-```nim
-proc `$`(a: Vec2): string {.raises: [ValueError].}
-```
-
-## **proc** angle
-
-Angle of a Vec2.
-
-```nim
-proc angle(a: Vec2): float32 {.inline.}
-```
-
-## **proc** angleBetween
-
-Angle between 2 Vec2.
-
-```nim
-proc angleBetween(a: Vec2; b: Vec2): float32 {.inline.}
-```
-
-## **type** Vec3
-
-3D vector
-
-```nim
-Vec3 = object
- x*: float32
- y*: float32
- z*: float32
+proc vec2[T](x`gensym7: GVec2[T]): Vec2 {.inline.}
```
## **proc** vec3
```nim
-proc vec3(x, y, z: float32): Vec3 {.inline.}
+proc vec3[T](x`gensym7: GVec3[T]): Vec3 {.inline.}
+```
+
+## **proc** vec4
+
+
+```nim
+proc vec4[T](x`gensym7: GVec4[T]): Vec4 {.inline.}
```
## **proc** vec3
```nim
-proc vec3(v: float32): Vec3 {.inline.}
+proc vec3[T](x`gensym7: GVec2[T]): Vec3 {.inline.}
```
-## **proc** vec3
+## **proc** vec4
```nim
-proc vec3(a: Vec3): Vec3 {.inline.}
+proc vec4[T](x`gensym7: GVec3[T]): Vec4 {.inline.}
```
-## **const** X_DIR
+## **proc** dvec2
```nim
-X_DIR = (x: 1.0, y: 0.0, z: 0.0)
+proc dvec2(x`gensym8, y`gensym8: float64): DVec2 {.inline.}
```
-## **const** Y_DIR
+## **proc** dvec3
```nim
-Y_DIR = (x: 0.0, y: 1.0, z: 0.0)
+proc dvec3(x`gensym8, y`gensym8, z`gensym8: float64): DVec3 {.inline, raises: [].}
```
-## **const** Z_DIR
+## **proc** dvec4
```nim
-Z_DIR = (x: 0.0, y: 0.0, z: 1.0)
+proc dvec4(x`gensym8, y`gensym8, z`gensym8, w`gensym8: float64): DVec4 {.inline, raises: [].}
```
-## **proc** `~=`
+## **proc** dvec2
```nim
-proc `~=`(a, b: Vec3): bool
+proc dvec2(x`gensym8: float64): DVec2 {.inline.}
```
-## **proc** `+`
+## **proc** dvec3
```nim
-proc `+`(a, b: Vec3): Vec3 {.inline.}
+proc dvec3(x`gensym8: float64): DVec3 {.inline.}
```
-## **proc** `-`
+## **proc** dvec4
```nim
-proc `-`(a, b: Vec3): Vec3 {.inline.}
+proc dvec4(x`gensym8: float64): DVec4 {.inline.}
```
-## **proc** `-`
+## **proc** dvec2
```nim
-proc `-`(a: Vec3): Vec3 {.inline.}
+proc dvec2[T](x`gensym8: GVec2[T]): DVec2 {.inline.}
```
-## **proc** `*`
+## **proc** dvec3
```nim
-proc `*`(a: Vec3; b: float32): Vec3 {.inline.}
+proc dvec3[T](x`gensym8: GVec3[T]): DVec3 {.inline.}
```
-## **proc** `*`
+## **proc** dvec4
```nim
-proc `*`(a: float32; b: Vec3): Vec3 {.inline.}
+proc dvec4[T](x`gensym8: GVec4[T]): DVec4 {.inline.}
```
-## **proc** `/`
+## **proc** dvec3
```nim
-proc `/`(a: Vec3; b: float32): Vec3 {.inline.}
+proc dvec3[T](x`gensym8: GVec2[T]): DVec3 {.inline.}
```
-## **proc** `/`
+## **proc** dvec4
```nim
-proc `/`(a: float32; b: Vec3): Vec3 {.inline.}
+proc dvec4[T](x`gensym8: GVec3[T]): DVec4 {.inline.}
```
-## **proc** `+=`
+## **proc** x
```nim
-proc `+=`(a: var Vec3; b: Vec3) {.inline.}
+proc x[T](a: var GVec2[T]): var T {.inline.}
```
-## **proc** `-=`
+## **proc** y
```nim
-proc `-=`(a: var Vec3; b: Vec3) {.inline.}
+proc y[T](a: var GVec2[T]): var T {.inline.}
```
-## **proc** `*=`
+## **proc** x
```nim
-proc `*=`(a: var Vec3; b: float32) {.inline.}
+proc x[T](a: var GVec3[T]): var T {.inline.}
```
-## **proc** `/=`
+## **proc** y
```nim
-proc `/=`(a: var Vec3; b: float32) {.inline.}
+proc y[T](a: var GVec3[T]): var T {.inline.}
```
-## **proc** zero
+## **proc** z
```nim
-proc zero(a: var Vec3) {.inline.}
+proc z[T](a: var GVec3[T]): var T {.inline.}
```
-## **proc** `-`
+## **proc** x
```nim
-proc `-`(a: var Vec3): Vec3 {.inline.}
+proc x[T](a: var GVec4[T]): var T {.inline.}
```
-## **proc** hash
+## **proc** y
```nim
-proc hash(a: Vec3): Hash {.inline.}
+proc y[T](a: var GVec4[T]): var T {.inline.}
```
-## **proc** lengthSq
+## **proc** z
```nim
-proc lengthSq(a: Vec3): float32 {.inline.}
+proc z[T](a: var GVec4[T]): var T {.inline.}
```
-## **proc** length
+## **proc** w
```nim
-proc length(a: Vec3): float32 {.inline.}
+proc w[T](a: var GVec4[T]): var T {.inline.}
```
-## **proc** length=
+## **proc** x
```nim
-proc length=(a: var Vec3; b: float32) {.inline.}
+proc x[T](a: GVec2[T]): T {.inline.}
```
-## **proc** floor
+## **proc** x
```nim
-proc floor(a: Vec3): Vec3 {.inline.}
+proc x[T](a: GVec3[T]): T {.inline.}
```
-## **proc** round
+## **proc** x
```nim
-proc round(a: Vec3): Vec3 {.inline.}
+proc x[T](a: GVec4[T]): T {.inline.}
```
-## **proc** ceil
+## **proc** y
```nim
-proc ceil(a: Vec3): Vec3 {.inline.}
+proc y[T](a: GVec2[T]): T {.inline.}
```
-## **proc** normalize
+## **proc** y
```nim
-proc normalize(a: Vec3): Vec3 {.inline.}
+proc y[T](a: GVec3[T]): T {.inline.}
```
-## **proc** cross
+## **proc** y
```nim
-proc cross(a, b: Vec3): Vec3 {.inline.}
+proc y[T](a: GVec4[T]): T {.inline.}
```
-## **proc** computeNormal
+## **proc** z
```nim
-proc computeNormal(a, b, c: Vec3): Vec3
+proc z[T](a: GVec2[T]): T {.inline.}
```
-## **proc** dot
+## **proc** z
```nim
-proc dot(a, b: Vec3): float32 {.inline.}
+proc z[T](a: GVec3[T]): T {.inline.}
```
-## **proc** dir
+## **proc** z
```nim
-proc dir(at, to: Vec3): Vec3 {.inline.}
+proc z[T](a: GVec4[T]): T {.inline.}
```
-## **proc** dist
+## **proc** w
```nim
-proc dist(at, to: Vec3): float32 {.inline.}
+proc w[T](a: GVec2[T]): T {.inline.}
```
-## **proc** distSq
+## **proc** w
```nim
-proc distSq(at, to: Vec3): float32 {.inline.}
+proc w[T](a: GVec3[T]): T {.inline.}
```
-## **proc** lerp
+## **proc** w
```nim
-proc lerp(a, b: Vec3; v: float32): Vec3 {.inline.}
+proc w[T](a: GVec4[T]): T {.inline.}
```
-## **proc** quantize
+## **proc** x=
```nim
-proc quantize(v: Vec3; n: float32): Vec3
+proc x=[T](a: var GVec234[T]; value: T) {.inline.}
```
-## **proc** angleBetween
+## **proc** y=
```nim
-proc angleBetween(a, b: Vec3): float32
+proc y=[T](a: var GVec234[T]; value: T) {.inline.}
```
-## **proc** `[]`
+## **proc** z=
```nim
-proc `[]`(a: Vec3; i: int): float32
+proc z=[T](a: var GVec34[T]; value: T) {.inline.}
```
-## **proc** `[]=`
+## **proc** w=
```nim
-proc `[]=`(a: var Vec3; i: int; b: float32)
+proc w=[T](a: var GVec4[T]; value: T) {.inline.}
```
## **proc** xy
```nim
-proc xy(a: Vec3): Vec2 {.inline.}
+proc xy[T](a: GVec234[T]): GVec2[T] {.inline.}
```
## **proc** xz
```nim
-proc xz(a: Vec3): Vec2 {.inline.}
+proc xz[T](a: GVec234[T]): GVec2[T] {.inline.}
```
## **proc** yx
```nim
-proc yx(a: Vec3): Vec2 {.inline.}
+proc yx[T](a: GVec234[T]): GVec2[T] {.inline.}
```
## **proc** yz
```nim
-proc yz(a: Vec3): Vec2 {.inline.}
+proc yz[T](a: GVec234[T]): GVec2[T] {.inline.}
```
## **proc** zx
```nim
-proc zx(a: Vec3): Vec2 {.inline.}
+proc zx[T](a: GVec234[T]): GVec2[T] {.inline.}
```
## **proc** zy
```nim
-proc zy(a: Vec3): Vec2 {.inline.}
+proc zy[T](a: GVec234[T]): GVec2[T] {.inline.}
```
## **proc** xxx
```nim
-proc xxx(a: Vec3): Vec3 {.inline.}
+proc xxx[T](a: GVec34[T]): GVec3[T] {.inline.}
```
## **proc** xxy
```nim
-proc xxy(a: Vec3): Vec3 {.inline.}
+proc xxy[T](a: GVec34[T]): GVec3[T] {.inline.}
```
## **proc** xxz
```nim
-proc xxz(a: Vec3): Vec3 {.inline.}
+proc xxz[T](a: GVec34[T]): GVec3[T] {.inline.}
```
## **proc** xyx
```nim
-proc xyx(a: Vec3): Vec3 {.inline.}
+proc xyx[T](a: GVec34[T]): GVec3[T] {.inline.}
```
## **proc** xyy
```nim
-proc xyy(a: Vec3): Vec3 {.inline.}
+proc xyy[T](a: GVec34[T]): GVec3[T] {.inline.}
```
## **proc** xyz
```nim
-proc xyz(a: Vec3): Vec3 {.inline.}
+proc xyz[T](a: GVec34[T]): GVec3[T] {.inline.}
```
## **proc** xzx
```nim
-proc xzx(a: Vec3): Vec3 {.inline.}
+proc xzx[T](a: GVec34[T]): GVec3[T] {.inline.}
```
## **proc** xzy
```nim
-proc xzy(a: Vec3): Vec3 {.inline.}
+proc xzy[T](a: GVec34[T]): GVec3[T] {.inline.}
```
## **proc** xzz
```nim
-proc xzz(a: Vec3): Vec3 {.inline.}
+proc xzz[T](a: GVec34[T]): GVec3[T] {.inline.}
```
## **proc** yxx
```nim
-proc yxx(a: Vec3): Vec3 {.inline.}
+proc yxx[T](a: GVec34[T]): GVec3[T] {.inline.}
```
## **proc** yxy
```nim
-proc yxy(a: Vec3): Vec3 {.inline.}
+proc yxy[T](a: GVec34[T]): GVec3[T] {.inline.}
```
## **proc** yxz
```nim
-proc yxz(a: Vec3): Vec3 {.inline.}
+proc yxz[T](a: GVec34[T]): GVec3[T] {.inline.}
```
## **proc** yyx
```nim
-proc yyx(a: Vec3): Vec3 {.inline.}
+proc yyx[T](a: GVec34[T]): GVec3[T] {.inline.}
```
## **proc** yyy
```nim
-proc yyy(a: Vec3): Vec3 {.inline.}
+proc yyy[T](a: GVec34[T]): GVec3[T] {.inline.}
```
## **proc** yyz
```nim
-proc yyz(a: Vec3): Vec3 {.inline.}
+proc yyz[T](a: GVec34[T]): GVec3[T] {.inline.}
```
## **proc** yzx
```nim
-proc yzx(a: Vec3): Vec3 {.inline.}
+proc yzx[T](a: GVec34[T]): GVec3[T] {.inline.}
```
## **proc** yzy
```nim
-proc yzy(a: Vec3): Vec3 {.inline.}
+proc yzy[T](a: GVec34[T]): GVec3[T] {.inline.}
```
## **proc** yzz
```nim
-proc yzz(a: Vec3): Vec3 {.inline.}
+proc yzz[T](a: GVec34[T]): GVec3[T] {.inline.}
```
## **proc** zxx
```nim
-proc zxx(a: Vec3): Vec3 {.inline.}
+proc zxx[T](a: GVec34[T]): GVec3[T] {.inline.}
```
## **proc** zxy
```nim
-proc zxy(a: Vec3): Vec3 {.inline.}
+proc zxy[T](a: GVec34[T]): GVec3[T] {.inline.}
```
## **proc** zxz
```nim
-proc zxz(a: Vec3): Vec3 {.inline.}
+proc zxz[T](a: GVec34[T]): GVec3[T] {.inline.}
```
## **proc** zyx
```nim
-proc zyx(a: Vec3): Vec3 {.inline.}
+proc zyx[T](a: GVec34[T]): GVec3[T] {.inline.}
```
## **proc** zyy
```nim
-proc zyy(a: Vec3): Vec3 {.inline.}
+proc zyy[T](a: GVec34[T]): GVec3[T] {.inline.}
```
## **proc** zyz
```nim
-proc zyz(a: Vec3): Vec3 {.inline.}
+proc zyz[T](a: GVec34[T]): GVec3[T] {.inline.}
```
## **proc** zzx
```nim
-proc zzx(a: Vec3): Vec3 {.inline.}
+proc zzx[T](a: GVec34[T]): GVec3[T] {.inline.}
```
## **proc** zzy
```nim
-proc zzy(a: Vec3): Vec3 {.inline.}
+proc zzy[T](a: GVec34[T]): GVec3[T] {.inline.}
```
## **proc** zzz
```nim
-proc zzz(a: Vec3): Vec3 {.inline.}
-```
-
-## **proc** randVec3
-
-Generates a random unit vector based on http://mathworld.wolfram.com/SpherePointPicking.html
-
-```nim
-proc randVec3(r: var Rand): Vec3
-```
-
-## **proc** `$`
-
-
-```nim
-proc `$`(a: Vec3): string {.raises: [ValueError].}
-```
-
-## **type** Vec4
-
-4D Vector.
-
-```nim
-Vec4 = object
- x*: float32
- y*: float32
- z*: float32
- w*: float32
-```
-
-## **proc** vec4
-
-
-```nim
-proc vec4(x, y, z, w: float32): Vec4 {.inline.}
-```
-
-## **proc** vec4
-
-
-```nim
-proc vec4(v: float32): Vec4 {.inline.}
-```
-
-## **proc** `~=`
-
-
-```nim
-proc `~=`(a, b: Vec4): bool
+proc zzz[T](a: GVec34[T]): GVec3[T] {.inline.}
```
## **proc** `+`
```nim
-proc `+`(a, b: Vec4): Vec4 {.inline.}
+proc `+`[T](a`gensym9, b`gensym9: GVec2[T]): GVec2[T] {.inline.}
+```
+
+## **proc** `+`
+
+
+```nim
+proc `+`[T](a`gensym9, b`gensym9: GVec3[T]): GVec3[T] {.inline.}
+```
+
+## **proc** `+`
+
+
+```nim
+proc `+`[T](a`gensym9, b`gensym9: GVec4[T]): GVec4[T] {.inline.}
+```
+
+## **proc** `+`
+
+
+```nim
+proc `+`[T](a`gensym9: GVec2[T]; b`gensym9: T): GVec2[T] {.inline.}
+```
+
+## **proc** `+`
+
+
+```nim
+proc `+`[T](a`gensym9: GVec3[T]; b`gensym9: T): GVec3[T] {.inline.}
+```
+
+## **proc** `+`
+
+
+```nim
+proc `+`[T](a`gensym9: GVec4[T]; b`gensym9: T): GVec4[T] {.inline.}
+```
+
+## **proc** `+`
+
+
+```nim
+proc `+`[T](a`gensym9: T; b`gensym9: GVec2[T]): GVec2[T] {.inline.}
+```
+
+## **proc** `+`
+
+
+```nim
+proc `+`[T](a`gensym9: T; b`gensym9: GVec3[T]): GVec3[T] {.inline.}
+```
+
+## **proc** `+`
+
+
+```nim
+proc `+`[T](a`gensym9: T; b`gensym9: GVec4[T]): GVec4[T] {.inline.}
```
## **proc** `-`
```nim
-proc `-`(a, b: Vec4): Vec4 {.inline.}
+proc `-`[T](a`gensym10, b`gensym10: GVec2[T]): GVec2[T] {.inline.}
```
## **proc** `-`
```nim
-proc `-`(a: Vec4): Vec4 {.inline.}
+proc `-`[T](a`gensym10, b`gensym10: GVec3[T]): GVec3[T] {.inline.}
+```
+
+## **proc** `-`
+
+
+```nim
+proc `-`[T](a`gensym10, b`gensym10: GVec4[T]): GVec4[T] {.inline.}
+```
+
+## **proc** `-`
+
+
+```nim
+proc `-`[T](a`gensym10: GVec2[T]; b`gensym10: T): GVec2[T] {.inline.}
+```
+
+## **proc** `-`
+
+
+```nim
+proc `-`[T](a`gensym10: GVec3[T]; b`gensym10: T): GVec3[T] {.inline.}
+```
+
+## **proc** `-`
+
+
+```nim
+proc `-`[T](a`gensym10: GVec4[T]; b`gensym10: T): GVec4[T] {.inline.}
+```
+
+## **proc** `-`
+
+
+```nim
+proc `-`[T](a`gensym10: T; b`gensym10: GVec2[T]): GVec2[T] {.inline.}
+```
+
+## **proc** `-`
+
+
+```nim
+proc `-`[T](a`gensym10: T; b`gensym10: GVec3[T]): GVec3[T] {.inline.}
+```
+
+## **proc** `-`
+
+
+```nim
+proc `-`[T](a`gensym10: T; b`gensym10: GVec4[T]): GVec4[T] {.inline.}
```
## **proc** `*`
```nim
-proc `*`(a: Vec4; b: float32): Vec4 {.inline.}
+proc `*`[T](a`gensym11, b`gensym11: GVec2[T]): GVec2[T] {.inline.}
```
## **proc** `*`
```nim
-proc `*`(a: float32; b: Vec4): Vec4 {.inline.}
+proc `*`[T](a`gensym11, b`gensym11: GVec3[T]): GVec3[T] {.inline.}
+```
+
+## **proc** `*`
+
+
+```nim
+proc `*`[T](a`gensym11, b`gensym11: GVec4[T]): GVec4[T] {.inline.}
+```
+
+## **proc** `*`
+
+
+```nim
+proc `*`[T](a`gensym11: GVec2[T]; b`gensym11: T): GVec2[T] {.inline.}
+```
+
+## **proc** `*`
+
+
+```nim
+proc `*`[T](a`gensym11: GVec3[T]; b`gensym11: T): GVec3[T] {.inline.}
+```
+
+## **proc** `*`
+
+
+```nim
+proc `*`[T](a`gensym11: GVec4[T]; b`gensym11: T): GVec4[T] {.inline.}
+```
+
+## **proc** `*`
+
+
+```nim
+proc `*`[T](a`gensym11: T; b`gensym11: GVec2[T]): GVec2[T] {.inline.}
+```
+
+## **proc** `*`
+
+
+```nim
+proc `*`[T](a`gensym11: T; b`gensym11: GVec3[T]): GVec3[T] {.inline.}
+```
+
+## **proc** `*`
+
+
+```nim
+proc `*`[T](a`gensym11: T; b`gensym11: GVec4[T]): GVec4[T] {.inline.}
```
## **proc** `/`
```nim
-proc `/`(a: Vec4; b: float32): Vec4 {.inline.}
+proc `/`[T](a`gensym12, b`gensym12: GVec2[T]): GVec2[T] {.inline.}
```
## **proc** `/`
```nim
-proc `/`(a: float32; b: Vec4): Vec4 {.inline.}
+proc `/`[T](a`gensym12, b`gensym12: GVec3[T]): GVec3[T] {.inline.}
+```
+
+## **proc** `/`
+
+
+```nim
+proc `/`[T](a`gensym12, b`gensym12: GVec4[T]): GVec4[T] {.inline.}
+```
+
+## **proc** `/`
+
+
+```nim
+proc `/`[T](a`gensym12: GVec2[T]; b`gensym12: T): GVec2[T] {.inline.}
+```
+
+## **proc** `/`
+
+
+```nim
+proc `/`[T](a`gensym12: GVec3[T]; b`gensym12: T): GVec3[T] {.inline.}
+```
+
+## **proc** `/`
+
+
+```nim
+proc `/`[T](a`gensym12: GVec4[T]; b`gensym12: T): GVec4[T] {.inline.}
+```
+
+## **proc** `/`
+
+
+```nim
+proc `/`[T](a`gensym12: T; b`gensym12: GVec2[T]): GVec2[T] {.inline.}
+```
+
+## **proc** `/`
+
+
+```nim
+proc `/`[T](a`gensym12: T; b`gensym12: GVec3[T]): GVec3[T] {.inline.}
+```
+
+## **proc** `/`
+
+
+```nim
+proc `/`[T](a`gensym12: T; b`gensym12: GVec4[T]): GVec4[T] {.inline.}
+```
+
+## **proc** `mod`
+
+
+```nim
+proc `mod`[T](a`gensym13, b`gensym13: GVec2[T]): GVec2[T] {.inline.}
+```
+
+## **proc** `mod`
+
+
+```nim
+proc `mod`[T](a`gensym13, b`gensym13: GVec3[T]): GVec3[T] {.inline.}
+```
+
+## **proc** `mod`
+
+
+```nim
+proc `mod`[T](a`gensym13, b`gensym13: GVec4[T]): GVec4[T] {.inline.}
+```
+
+## **proc** `mod`
+
+
+```nim
+proc `mod`[T](a`gensym13: GVec2[T]; b`gensym13: T): GVec2[T] {.inline.}
+```
+
+## **proc** `mod`
+
+
+```nim
+proc `mod`[T](a`gensym13: GVec3[T]; b`gensym13: T): GVec3[T] {.inline.}
+```
+
+## **proc** `mod`
+
+
+```nim
+proc `mod`[T](a`gensym13: GVec4[T]; b`gensym13: T): GVec4[T] {.inline.}
+```
+
+## **proc** `mod`
+
+
+```nim
+proc `mod`[T](a`gensym13: T; b`gensym13: GVec2[T]): GVec2[T] {.inline.}
+```
+
+## **proc** `mod`
+
+
+```nim
+proc `mod`[T](a`gensym13: T; b`gensym13: GVec3[T]): GVec3[T] {.inline.}
+```
+
+## **proc** `mod`
+
+
+```nim
+proc `mod`[T](a`gensym13: T; b`gensym13: GVec4[T]): GVec4[T] {.inline.}
+```
+
+## **proc** `div`
+
+
+```nim
+proc `div`[T](a`gensym14, b`gensym14: GVec2[T]): GVec2[T] {.inline.}
+```
+
+## **proc** `div`
+
+
+```nim
+proc `div`[T](a`gensym14, b`gensym14: GVec3[T]): GVec3[T] {.inline.}
+```
+
+## **proc** `div`
+
+
+```nim
+proc `div`[T](a`gensym14, b`gensym14: GVec4[T]): GVec4[T] {.inline.}
+```
+
+## **proc** `div`
+
+
+```nim
+proc `div`[T](a`gensym14: GVec2[T]; b`gensym14: T): GVec2[T] {.inline.}
+```
+
+## **proc** `div`
+
+
+```nim
+proc `div`[T](a`gensym14: GVec3[T]; b`gensym14: T): GVec3[T] {.inline.}
+```
+
+## **proc** `div`
+
+
+```nim
+proc `div`[T](a`gensym14: GVec4[T]; b`gensym14: T): GVec4[T] {.inline.}
+```
+
+## **proc** `div`
+
+
+```nim
+proc `div`[T](a`gensym14: T; b`gensym14: GVec2[T]): GVec2[T] {.inline.}
+```
+
+## **proc** `div`
+
+
+```nim
+proc `div`[T](a`gensym14: T; b`gensym14: GVec3[T]): GVec3[T] {.inline.}
+```
+
+## **proc** `div`
+
+
+```nim
+proc `div`[T](a`gensym14: T; b`gensym14: GVec4[T]): GVec4[T] {.inline.}
```
## **proc** `+=`
```nim
-proc `+=`(a: var Vec4; b: Vec4) {.inline.}
+proc `+=`[T](a`gensym15: var GVec2[T]; b`gensym15: GVec2[T]) {.inline.}
+```
+
+## **proc** `+=`
+
+
+```nim
+proc `+=`[T](a`gensym15: var GVec3[T]; b`gensym15: GVec3[T]) {.inline.}
+```
+
+## **proc** `+=`
+
+
+```nim
+proc `+=`[T](a`gensym15: var GVec4[T]; b`gensym15: GVec4[T]) {.inline.}
+```
+
+## **proc** `+=`
+
+
+```nim
+proc `+=`[T](a`gensym15: var GVec2[T]; b`gensym15: T) {.inline.}
+```
+
+## **proc** `+=`
+
+
+```nim
+proc `+=`[T](a`gensym15: var GVec3[T]; b`gensym15: T) {.inline.}
+```
+
+## **proc** `+=`
+
+
+```nim
+proc `+=`[T](a`gensym15: var GVec4[T]; b`gensym15: T) {.inline.}
```
## **proc** `-=`
```nim
-proc `-=`(a: var Vec4; b: Vec4) {.inline.}
+proc `-=`[T](a`gensym16: var GVec2[T]; b`gensym16: GVec2[T]) {.inline.}
+```
+
+## **proc** `-=`
+
+
+```nim
+proc `-=`[T](a`gensym16: var GVec3[T]; b`gensym16: GVec3[T]) {.inline.}
+```
+
+## **proc** `-=`
+
+
+```nim
+proc `-=`[T](a`gensym16: var GVec4[T]; b`gensym16: GVec4[T]) {.inline.}
+```
+
+## **proc** `-=`
+
+
+```nim
+proc `-=`[T](a`gensym16: var GVec2[T]; b`gensym16: T) {.inline.}
+```
+
+## **proc** `-=`
+
+
+```nim
+proc `-=`[T](a`gensym16: var GVec3[T]; b`gensym16: T) {.inline.}
+```
+
+## **proc** `-=`
+
+
+```nim
+proc `-=`[T](a`gensym16: var GVec4[T]; b`gensym16: T) {.inline.}
```
## **proc** `*=`
```nim
-proc `*=`(a: var Vec4; b: float32) {.inline.}
+proc `*=`[T](a`gensym17: var GVec2[T]; b`gensym17: GVec2[T]) {.inline.}
+```
+
+## **proc** `*=`
+
+
+```nim
+proc `*=`[T](a`gensym17: var GVec3[T]; b`gensym17: GVec3[T]) {.inline.}
+```
+
+## **proc** `*=`
+
+
+```nim
+proc `*=`[T](a`gensym17: var GVec4[T]; b`gensym17: GVec4[T]) {.inline.}
+```
+
+## **proc** `*=`
+
+
+```nim
+proc `*=`[T](a`gensym17: var GVec2[T]; b`gensym17: T) {.inline.}
+```
+
+## **proc** `*=`
+
+
+```nim
+proc `*=`[T](a`gensym17: var GVec3[T]; b`gensym17: T) {.inline.}
+```
+
+## **proc** `*=`
+
+
+```nim
+proc `*=`[T](a`gensym17: var GVec4[T]; b`gensym17: T) {.inline.}
```
## **proc** `/=`
```nim
-proc `/=`(a: var Vec4; b: float32) {.inline.}
+proc `/=`[T](a`gensym18: var GVec2[T]; b`gensym18: GVec2[T]) {.inline.}
```
-## **proc** zero
+## **proc** `/=`
```nim
-proc zero(a: var Vec4) {.inline.}
+proc `/=`[T](a`gensym18: var GVec3[T]; b`gensym18: GVec3[T]) {.inline.}
```
-## **proc** hash
+## **proc** `/=`
```nim
-proc hash(a: Vec4): Hash {.inline.}
+proc `/=`[T](a`gensym18: var GVec4[T]; b`gensym18: GVec4[T]) {.inline.}
+```
+
+## **proc** `/=`
+
+
+```nim
+proc `/=`[T](a`gensym18: var GVec2[T]; b`gensym18: T) {.inline.}
+```
+
+## **proc** `/=`
+
+
+```nim
+proc `/=`[T](a`gensym18: var GVec3[T]; b`gensym18: T) {.inline.}
+```
+
+## **proc** `/=`
+
+
+```nim
+proc `/=`[T](a`gensym18: var GVec4[T]; b`gensym18: T) {.inline.}
+```
+
+## **proc** `-`
+
+
+```nim
+proc `-`[T](v`gensym19: GVec2[T]): GVec2[T] {.inline.}
+```
+
+## **proc** `-`
+
+
+```nim
+proc `-`[T](v`gensym19: GVec3[T]): GVec3[T] {.inline.}
+```
+
+## **proc** `-`
+
+
+```nim
+proc `-`[T](v`gensym19: GVec4[T]): GVec4[T] {.inline.}
+```
+
+## **proc** sin
+
+
+```nim
+proc sin[T](v`gensym20: GVec2[T]): GVec2[T] {.inline.}
+```
+
+## **proc** sin
+
+
+```nim
+proc sin[T](v`gensym20: GVec3[T]): GVec3[T] {.inline.}
+```
+
+## **proc** sin
+
+
+```nim
+proc sin[T](v`gensym20: GVec4[T]): GVec4[T] {.inline.}
+```
+
+## **proc** cos
+
+
+```nim
+proc cos[T](v`gensym21: GVec2[T]): GVec2[T] {.inline.}
+```
+
+## **proc** cos
+
+
+```nim
+proc cos[T](v`gensym21: GVec3[T]): GVec3[T] {.inline.}
+```
+
+## **proc** cos
+
+
+```nim
+proc cos[T](v`gensym21: GVec4[T]): GVec4[T] {.inline.}
+```
+
+## **proc** tan
+
+
+```nim
+proc tan[T](v`gensym22: GVec2[T]): GVec2[T] {.inline.}
+```
+
+## **proc** tan
+
+
+```nim
+proc tan[T](v`gensym22: GVec3[T]): GVec3[T] {.inline.}
+```
+
+## **proc** tan
+
+
+```nim
+proc tan[T](v`gensym22: GVec4[T]): GVec4[T] {.inline.}
+```
+
+## **proc** arcsin
+
+
+```nim
+proc arcsin[T](v`gensym23: GVec2[T]): GVec2[T] {.inline.}
+```
+
+## **proc** arcsin
+
+
+```nim
+proc arcsin[T](v`gensym23: GVec3[T]): GVec3[T] {.inline.}
+```
+
+## **proc** arcsin
+
+
+```nim
+proc arcsin[T](v`gensym23: GVec4[T]): GVec4[T] {.inline.}
+```
+
+## **proc** arccos
+
+
+```nim
+proc arccos[T](v`gensym24: GVec2[T]): GVec2[T] {.inline.}
+```
+
+## **proc** arccos
+
+
+```nim
+proc arccos[T](v`gensym24: GVec3[T]): GVec3[T] {.inline.}
+```
+
+## **proc** arccos
+
+
+```nim
+proc arccos[T](v`gensym24: GVec4[T]): GVec4[T] {.inline.}
+```
+
+## **proc** arctan
+
+
+```nim
+proc arctan[T](v`gensym25: GVec2[T]): GVec2[T] {.inline.}
+```
+
+## **proc** arctan
+
+
+```nim
+proc arctan[T](v`gensym25: GVec3[T]): GVec3[T] {.inline.}
+```
+
+## **proc** arctan
+
+
+```nim
+proc arctan[T](v`gensym25: GVec4[T]): GVec4[T] {.inline.}
+```
+
+## **proc** sinh
+
+
+```nim
+proc sinh[T](v`gensym26: GVec2[T]): GVec2[T] {.inline.}
+```
+
+## **proc** sinh
+
+
+```nim
+proc sinh[T](v`gensym26: GVec3[T]): GVec3[T] {.inline.}
+```
+
+## **proc** sinh
+
+
+```nim
+proc sinh[T](v`gensym26: GVec4[T]): GVec4[T] {.inline.}
+```
+
+## **proc** cosh
+
+
+```nim
+proc cosh[T](v`gensym27: GVec2[T]): GVec2[T] {.inline.}
+```
+
+## **proc** cosh
+
+
+```nim
+proc cosh[T](v`gensym27: GVec3[T]): GVec3[T] {.inline.}
+```
+
+## **proc** cosh
+
+
+```nim
+proc cosh[T](v`gensym27: GVec4[T]): GVec4[T] {.inline.}
+```
+
+## **proc** tanh
+
+
+```nim
+proc tanh[T](v`gensym28: GVec2[T]): GVec2[T] {.inline.}
+```
+
+## **proc** tanh
+
+
+```nim
+proc tanh[T](v`gensym28: GVec3[T]): GVec3[T] {.inline.}
+```
+
+## **proc** tanh
+
+
+```nim
+proc tanh[T](v`gensym28: GVec4[T]): GVec4[T] {.inline.}
+```
+
+## **proc** exp2
+
+
+```nim
+proc exp2[T](v`gensym29: GVec2[T]): GVec2[T] {.inline.}
+```
+
+## **proc** exp2
+
+
+```nim
+proc exp2[T](v`gensym29: GVec3[T]): GVec3[T] {.inline.}
+```
+
+## **proc** exp2
+
+
+```nim
+proc exp2[T](v`gensym29: GVec4[T]): GVec4[T] {.inline.}
+```
+
+## **proc** inversesqrt
+
+
+```nim
+proc inversesqrt[T](v`gensym30: GVec2[T]): GVec2[T] {.inline.}
+```
+
+## **proc** inversesqrt
+
+
+```nim
+proc inversesqrt[T](v`gensym30: GVec3[T]): GVec3[T] {.inline.}
+```
+
+## **proc** inversesqrt
+
+
+```nim
+proc inversesqrt[T](v`gensym30: GVec4[T]): GVec4[T] {.inline.}
+```
+
+## **proc** exp
+
+
+```nim
+proc exp[T](v`gensym31: GVec2[T]): GVec2[T] {.inline.}
+```
+
+## **proc** exp
+
+
+```nim
+proc exp[T](v`gensym31: GVec3[T]): GVec3[T] {.inline.}
+```
+
+## **proc** exp
+
+
+```nim
+proc exp[T](v`gensym31: GVec4[T]): GVec4[T] {.inline.}
+```
+
+## **proc** ln
+
+
+```nim
+proc ln[T](v`gensym32: GVec2[T]): GVec2[T] {.inline.}
+```
+
+## **proc** ln
+
+
+```nim
+proc ln[T](v`gensym32: GVec3[T]): GVec3[T] {.inline.}
+```
+
+## **proc** ln
+
+
+```nim
+proc ln[T](v`gensym32: GVec4[T]): GVec4[T] {.inline.}
+```
+
+## **proc** log2
+
+
+```nim
+proc log2[T](v`gensym33: GVec2[T]): GVec2[T] {.inline.}
+```
+
+## **proc** log2
+
+
+```nim
+proc log2[T](v`gensym33: GVec3[T]): GVec3[T] {.inline.}
+```
+
+## **proc** log2
+
+
+```nim
+proc log2[T](v`gensym33: GVec4[T]): GVec4[T] {.inline.}
+```
+
+## **proc** sqrt
+
+
+```nim
+proc sqrt[T](v`gensym34: GVec2[T]): GVec2[T] {.inline.}
+```
+
+## **proc** sqrt
+
+
+```nim
+proc sqrt[T](v`gensym34: GVec3[T]): GVec3[T] {.inline.}
+```
+
+## **proc** sqrt
+
+
+```nim
+proc sqrt[T](v`gensym34: GVec4[T]): GVec4[T] {.inline.}
```
## **proc** floor
```nim
-proc floor(a: Vec4): Vec4 {.inline.}
+proc floor[T](v`gensym35: GVec2[T]): GVec2[T] {.inline.}
```
-## **proc** round
+## **proc** floor
```nim
-proc round(a: Vec4): Vec4 {.inline.}
+proc floor[T](v`gensym35: GVec3[T]): GVec3[T] {.inline.}
```
-## **proc** ceil
+## **proc** floor
```nim
-proc ceil(a: Vec4): Vec4 {.inline.}
+proc floor[T](v`gensym35: GVec4[T]): GVec4[T] {.inline.}
```
-## **proc** `[]`
+## **proc** ciel
```nim
-proc `[]`(a: Vec4; i: int): float32
+proc ciel[T](v`gensym36: GVec2[T]): GVec2[T] {.inline.}
```
-## **proc** `[]=`
+## **proc** ciel
```nim
-proc `[]=`(a: var Vec4; i: int; b: float32)
+proc ciel[T](v`gensym36: GVec3[T]): GVec3[T] {.inline.}
+```
+
+## **proc** ciel
+
+
+```nim
+proc ciel[T](v`gensym36: GVec4[T]): GVec4[T] {.inline.}
+```
+
+## **proc** abs
+
+
+```nim
+proc abs[T](v`gensym37: GVec2[T]): GVec2[T] {.inline.}
+```
+
+## **proc** abs
+
+
+```nim
+proc abs[T](v`gensym37: GVec3[T]): GVec3[T] {.inline.}
+```
+
+## **proc** abs
+
+
+```nim
+proc abs[T](v`gensym37: GVec4[T]): GVec4[T] {.inline.}
+```
+
+## **proc** `~=`
+
+Almost equal.
+
+```nim
+proc `~=`[T](a, b: GVec2[T]): bool {.inline.}
+```
+
+## **proc** `~=`
+
+Almost equal.
+
+```nim
+proc `~=`[T](a, b: GVec3[T]): bool {.inline.}
+```
+
+## **proc** `~=`
+
+Almost equal.
+
+```nim
+proc `~=`[T](a, b: GVec4[T]): bool {.inline.}
+```
+
+## **proc** length
+
+
+```nim
+proc length[T](a: GVec2[T]): T {.inline.}
+```
+
+## **proc** length
+
+
+```nim
+proc length[T](a: GVec3[T]): T {.inline.}
+```
+
+## **proc** length
+
+
+```nim
+proc length[T](a: GVec4[T]): T {.inline.}
+```
+
+## **proc** lengthSq
+
+
+```nim
+proc lengthSq[T](a: GVec2[T]): T {.inline.}
+```
+
+## **proc** lengthSq
+
+
+```nim
+proc lengthSq[T](a: GVec3[T]): T {.inline.}
+```
+
+## **proc** lengthSq
+
+
+```nim
+proc lengthSq[T](a: GVec4[T]): T {.inline.}
+```
+
+## **proc** normalize
+
+
+```nim
+proc normalize[T](a: GVec234[T]): type(a) {.inline.}
```
## **proc** lerp
```nim
-proc lerp(a: Vec4; b: Vec4; v: float32): Vec4 {.inline.}
+proc lerp[T: SomeFloat](a, b: GVec234[T]; v: T): type(a) {.inline.}
```
-## **proc** xyz
+## **proc** dot
```nim
-proc xyz(a: Vec4): Vec3 {.inline.}
+proc dot[T](a, b: GVec2[T]): T {.inline.}
```
-## **proc** `$`
+## **proc** dot
```nim
-proc `$`(a: Vec4): string {.raises: [ValueError].}
+proc dot[T](a, b: GVec3[T]): T {.inline.}
```
-## **proc** vec3
+## **proc** dot
```nim
-proc vec3(a: Vec2; z = 0.0): Vec3 {.inline.}
+proc dot[T](a, b: GVec4[T]): T {.inline.}
```
-## **proc** vec4
+## **proc** cross
```nim
-proc vec4(a: Vec3; w = 0.0): Vec4 {.inline.}
+proc cross[T](a, b: GVec3[T]): GVec3[T] {.inline.}
```
-## **proc** vec4
+## **proc** dist
```nim
-proc vec4(a: Vec2; z = 0.0; w = 0.0): Vec4 {.inline.}
+proc dist[T](at, to: GVec234[T]): T {.inline.}
+```
+
+## **proc** distSq
+
+
+```nim
+proc distSq[T](at, to: GVec234[T]): T {.inline.}
+```
+
+## **proc** dir
+
+
+```nim
+proc dir[T](at, to: GVec234[T]): type(to) {.inline.}
+```
+
+## **proc** dir
+
+
+```nim
+proc dir[T](angle: T): GVec2[T] {.inline.}
+```
+
+## **type** GMat2
+
+
+```nim
+GMat2[T] = array[2, GVec2[T]]
+```
+
+## **type** GMat3
+
+
+```nim
+GMat3[T] = array[3, GVec3[T]]
+```
+
+## **type** GMat4
+
+
+```nim
+GMat4[T] = array[4, GVec4[T]]
+```
+
+## **type** Mat2
+
+
+```nim
+Mat2 = GMat2[float32]
```
## **type** Mat3
-3x3 Matrix
```nim
-Mat3 = array[9, float32]
+Mat3 = GMat3[float32]
```
-## **proc** `[]`
+## **type** Mat4
```nim
-proc `[]`(a: Mat3; i, j: int): float32 {.inline.}
+Mat4 = GMat4[float32]
```
-## **proc** `[]=`
+## **type** DMat2
```nim
-proc `[]=`(a: var Mat3; i, j: int; v: float32) {.inline.}
+DMat2 = GMat2[float64]
+```
+
+## **type** DMat3
+
+
+```nim
+DMat3 = GMat3[float64]
+```
+
+## **type** DMat4
+
+
+```nim
+DMat4 = GMat4[float64]
+```
+
+## **proc** mat2
+
+
+```nim
+proc mat2(a`gensym38, b`gensym38, c`gensym38, d`gensym38: float32): Mat2 {. inline.}
```
## **proc** mat3
```nim
-proc mat3(a, b, c, d, e, f, g, h, i: float32): Mat3 {.inline, tags: [].}
+proc mat3(a`gensym38, b`gensym38, c`gensym38, d`gensym38, e`gensym38, f`gensym38, g`gensym38, h`gensym38, i`gensym38: float32): Mat3 {. inline.}
+```
+
+## **proc** mat4
+
+
+```nim
+proc mat4(a`gensym38, b`gensym38, c`gensym38, d`gensym38, e`gensym38, f`gensym38, g`gensym38, h`gensym38, i`gensym38, j`gensym38, k`gensym38, l`gensym38, m`gensym38, n`gensym38, o`gensym38, p`gensym38: float32): Mat4 {. inline.}
+```
+
+## **proc** mat2
+
+
+```nim
+proc mat2(a`gensym38, b`gensym38: GVec2[float32]): Mat2 {.inline, tags: [].}
```
## **proc** mat3
```nim
-proc mat3(a: Mat3): Mat3 {.inline.}
+proc mat3(a`gensym38, b`gensym38, c`gensym38: GVec3[float32]): Mat3 {.inline, raises: [].}
```
-## **proc** `~=`
+## **proc** mat4
```nim
-proc `~=`(a: Mat3; b: Mat3): bool
+proc mat4(a`gensym38, b`gensym38, c`gensym38, d`gensym38: GVec4[float32]): Mat4 {. inline.}
```
-## **proc** identity
+## **proc** mat2
```nim
-proc identity(a: var Mat3) {.inline.}
+proc mat2(m`gensym38: GMat3[float32]): Mat2 {.inline.}
+```
+
+## **proc** mat3
+
+
+```nim
+proc mat3(m`gensym38: GMat4[float32]): Mat3 {.inline.}
+```
+
+## **proc** mat3
+
+
+```nim
+proc mat3(m`gensym38: GMat2[float32]): Mat3 {.inline.}
+```
+
+## **proc** mat4
+
+
+```nim
+proc mat4(m`gensym38: GMat3[float32]): Mat4 {.inline.}
+```
+
+## **proc** mat2
+
+
+```nim
+proc mat2(): Mat2 {.inline.}
```
## **proc** mat3
@@ -1131,147 +2293,6 @@ proc identity(a: var Mat3) {.inline.}
proc mat3(): Mat3 {.inline.}
```
-## **proc** transpose
-
-
-```nim
-proc transpose(a: Mat3): Mat3 {.inline.}
-```
-
-## **proc** `$`
-
-
-```nim
-proc `$`(a: Mat3): string {.raises: [ValueError].}
-```
-
-## **proc** `*`
-
-
-```nim
-proc `*`(a, b: Mat3): Mat3
-```
-
-## **proc** scale
-
-
-```nim
-proc scale(a: Mat3; v: Vec2): Mat3 {.inline.}
-```
-
-## **proc** scale
-
-
-```nim
-proc scale(a: Mat3; v: Vec3): Mat3 {.inline.}
-```
-
-## **proc** translate
-
-
-```nim
-proc translate(v: Vec2): Mat3 {.inline.}
-```
-
-## **proc** scale
-
-
-```nim
-proc scale(v: Vec2): Mat3 {.inline.}
-```
-
-## **proc** rotationMat3
-
-
-```nim
-proc rotationMat3(angle: float32): Mat3 {.inline.}
-```
-
-## **proc** rotate
-
-
-```nim
-proc rotate(a: Mat3; angle: float32): Mat3 {.inline.}
-```
-
-## **proc** `*`
-
-
-```nim
-proc `*`(a: Mat3; b: Vec2): Vec2
-```
-
-## **proc** `*`
-
-
-```nim
-proc `*`(a: Mat3; b: Vec3): Vec3
-```
-
-## **proc** inverse
-
-
-```nim
-proc inverse(a: Mat3): Mat3
-```
-
-## **proc** pos
-
-
-```nim
-proc pos(a: Mat3): Vec2 {.inline.}
-```
-
-## **proc** pos=
-
-
-```nim
-proc pos=(a: var Mat3; b: Vec2) {.inline.}
-```
-
-## **type** Mat4
-
-4x4 Matrix - OpenGL row order
-
-```nim
-Mat4 = array[16, float32]
-```
-
-## **proc** `[]`
-
-
-```nim
-proc `[]`(a: Mat4; i, j: int): float32
-```
-
-## **proc** `[]=`
-
-
-```nim
-proc `[]=`(a: var Mat4; i, j: int; v: float32)
-```
-
-## **proc** mat4
-
-
-```nim
-proc mat4(v0, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15: float32): Mat4 {. inline.}
-```
-
-## **proc** mat4
-
-
-```nim
-proc mat4(a: Mat4): Mat4 {.inline.}
-```
-
-## **proc** identity
-
-
-```nim
-proc identity(): Mat4 {.inline.}
-```
-
## **proc** mat4
@@ -1279,469 +2300,426 @@ proc identity(): Mat4 {.inline.}
proc mat4(): Mat4 {.inline.}
```
-## **proc** `~=`
+## **proc** dmat2
```nim
-proc `~=`(a: Mat4; b: Mat4): bool
+proc dmat2(a`gensym39, b`gensym39, c`gensym39, d`gensym39: float64): DMat2 {. inline.}
```
-## **proc** transpose
+## **proc** dmat3
```nim
-proc transpose(a: Mat4): Mat4 {.inline.}
+proc dmat3(a`gensym39, b`gensym39, c`gensym39, d`gensym39, e`gensym39, f`gensym39, g`gensym39, h`gensym39, i`gensym39: float64): DMat3 {. inline.}
```
-## **proc** determinant
+## **proc** dmat4
```nim
-proc determinant(a: Mat4): float32
+proc dmat4(a`gensym39, b`gensym39, c`gensym39, d`gensym39, e`gensym39, f`gensym39, g`gensym39, h`gensym39, i`gensym39, j`gensym39, k`gensym39, l`gensym39, m`gensym39, n`gensym39, o`gensym39, p`gensym39: float64): DMat4 {.inline.}
```
-## **proc** inverse
+## **proc** dmat2
```nim
-proc inverse(a: Mat4): Mat4
+proc dmat2(a`gensym39, b`gensym39: GVec2[float64]): DMat2 {.inline, tags: [].}
```
-## **proc** `*`
+## **proc** dmat3
```nim
-proc `*`(a, b: Mat4): Mat4
+proc dmat3(a`gensym39, b`gensym39, c`gensym39: GVec3[float64]): DMat3 {.inline, raises: [].}
```
-## **proc** `*`
+## **proc** dmat4
```nim
-proc `*`(a: Mat4; b: Vec3): Vec3
+proc dmat4(a`gensym39, b`gensym39, c`gensym39, d`gensym39: GVec4[float64]): DMat4 {. inline.}
```
-## **proc** `*`
+## **proc** dmat2
```nim
-proc `*`(a: Mat4; b: Vec4): Vec4
+proc dmat2(m`gensym39: GMat3[float64]): DMat2 {.inline.}
```
-## **proc** right
+## **proc** dmat3
```nim
-proc right(a: Mat4): Vec3 {.inline.}
+proc dmat3(m`gensym39: GMat4[float64]): DMat3 {.inline.}
```
-## **proc** right=
+## **proc** dmat3
```nim
-proc right=(a: var Mat4; b: Vec3) {.inline.}
+proc dmat3(m`gensym39: GMat2[float64]): DMat3 {.inline.}
```
-## **proc** up
+## **proc** dmat4
```nim
-proc up(a: Mat4): Vec3 {.inline.}
+proc dmat4(m`gensym39: GMat3[float64]): DMat4 {.inline.}
```
-## **proc** up=
+## **proc** dmat2
```nim
-proc up=(a: var Mat4; b: Vec3) {.inline.}
+proc dmat2(): DMat2 {.inline.}
```
-## **proc** forward
+## **proc** dmat3
```nim
-proc forward(a: Mat4): Vec3 {.inline.}
+proc dmat3(): DMat3 {.inline.}
```
-## **proc** forward=
+## **proc** dmat4
```nim
-proc forward=(a: var Mat4; b: Vec3) {.inline.}
-```
-
-## **proc** pos
-
-
-```nim
-proc pos(a: Mat4): Vec3 {.inline.}
-```
-
-## **proc** pos=
-
-
-```nim
-proc pos=(a: var Mat4; b: Vec3) {.inline.}
-```
-
-## **proc** rotationOnly
-
-
-```nim
-proc rotationOnly(a: Mat4): Mat4 {.inline.}
-```
-
-## **proc** dist
-
-
-```nim
-proc dist(a, b: Mat4): float32 {.inline.}
-```
-
-## **proc** translate
-
-
-```nim
-proc translate(v: Vec3): Mat4
-```
-
-## **proc** scale
-
-
-```nim
-proc scale(v: Vec3): Mat4
-```
-
-## **proc** hrp
-
-
-```nim
-proc hrp(m: Mat4): Vec3
-```
-
-## **proc** frustum
-
-
-```nim
-proc frustum(left, right, bottom, top, near, far: float32): Mat4
-```
-
-## **proc** perspective
-
-
-```nim
-proc perspective(fovy, aspect, near, far: float32): Mat4
-```
-
-## **proc** ortho
-
-
-```nim
-proc ortho(left, right, bottom, top, near, far: float32): Mat4
-```
-
-## **proc** lookAt
-
-
-```nim
-proc lookAt(eye, center, up: Vec3): Mat4
-```
-
-## **proc** mat3
-
-Gets rotation and translation, ignoring z coordinates.
-
-```nim
-proc mat3(m: Mat4): Mat3
-```
-
-## **proc** mat3Rotation
-
-Gets the rotational part of the 4x4 matrix.
-
-```nim
-proc mat3Rotation(m: Mat4): Mat3
-```
-
-## **proc** mat4
-
-Takes a 2d Mat3 with position and converts to a 3d matrix.
-
-```nim
-proc mat4(m: Mat3): Mat4
-```
-
-## **proc** mat4Rotation
-
-Gets the rotational part of the 3x3 matrix into a 4x4 matrix.
-
-```nim
-proc mat4Rotation(m: Mat3): Mat4
-```
-
-## **proc** `$`
-
-
-```nim
-proc `$`(a: Mat4): string {.raises: [ValueError].}
-```
-
-## **type** Quat
-
-
-```nim
-Quat = object
- x*: float32
- y*: float32
- z*: float32
- w*: float32
-```
-
-## **proc** quat
-
-
-```nim
-proc quat(x, y, z, w: float32): Quat {.inline.}
-```
-
-## **proc** `~=`
-
-
-```nim
-proc `~=`(a, b: Quat): bool
-```
-
-## **proc** conjugate
-
-
-```nim
-proc conjugate(q: Quat): Quat {.inline.}
-```
-
-## **proc** length
-
-
-```nim
-proc length(q: Quat): float32 {.inline.}
-```
-
-## **proc** normalize
-
-
-```nim
-proc normalize(q: Quat): Quat
-```
-
-## **proc** xyz
-
-
-```nim
-proc xyz(q: Quat): Vec3 {.inline.}
-```
-
-## **proc** xyz=
-
-
-```nim
-proc xyz=(q: var Quat; v: Vec3) {.inline.}
-```
-
-## **proc** `-`
-
-
-```nim
-proc `-`(a: var Quat): Quat {.inline.}
-```
-
-## **proc** `+`
-
-
-```nim
-proc `+`(a: Quat; b: Quat): Quat {.inline.}
-```
-
-## **proc** `*`
-
-Multiply the quaternion by a quaternion.
-
-```nim
-proc `*`(a, b: Quat): Quat
-```
-
-## **proc** `*`
-
-Multiply the quaternion by a float32.
-
-```nim
-proc `*`(q: Quat; v: float32): Quat {.inline.}
-```
-
-## **proc** `/`
-
-Divide the quaternion by a float32.
-
-```nim
-proc `/`(q: Quat; v: float32): Quat {.inline.}
-```
-
-## **proc** `*=`
-
-
-```nim
-proc `*=`(a: var Quat; b: float32) {.inline.}
-```
-
-## **proc** `/=`
-
-
-```nim
-proc `/=`(a: var Quat; b: float32) {.inline.}
-```
-
-## **proc** `*`
-
-Multiply the quaternion by a vector.
-
-```nim
-proc `*`(q: Quat; v: Vec3): Vec3
+proc dmat4(): DMat4 {.inline.}
```
## **proc** `[]`
```nim
-proc `[]`(a: var Quat; i: int; b: float32)
+proc `[]`[T](a: GMat234[T]; i, j: int): T {.inline.}
```
## **proc** `[]=`
```nim
-proc `[]=`(a: var Quat; i: int; b: float32)
+proc `[]=`[T](a: var GMat234[T]; i, j: int; v: T) {.inline.}
```
-## **proc** mat3
+## **proc** `~=`
```nim
-proc mat3(q: Quat): Mat3
+proc `~=`[T](a, b: GMat2[T]): bool {.inline.}
```
-## **proc** mat4
+## **proc** `~=`
```nim
-proc mat4(q: Quat): Mat4
+proc `~=`[T](a, b: GMat3[T]): bool {.inline.}
```
-## **proc** reciprocalSqrt
+## **proc** `~=`
```nim
-proc reciprocalSqrt(x: float32): float32 {.inline.}
+proc `~=`[T](a, b: GMat4[T]): bool {.inline.}
```
-## **proc** quat
+## **proc** `*`
```nim
-proc quat(m: Mat4): Quat
+proc `*`[T](a, b: GMat3[T]): GMat3[T] {.inline.}
```
-## **proc** fromAxisAngle
+## **proc** `*`
```nim
-proc fromAxisAngle(axis: Vec3; angle: float32): Quat
+proc `*`[T](a: GMat3[T]; b: GVec2[T]): GVec2[T] {.inline.}
```
-## **proc** toAxisAngle
+## **proc** `*`
```nim
-proc toAxisAngle(q: Quat; axis: var Vec3; angle: var float32)
+proc `*`[T](a, b: GMat4[T]): GMat4[T] {.inline.}
```
-## **proc** quat
+## **proc** `*`
```nim
-proc quat(heading, pitch, roll: float32): Quat
+proc `*`[T](a: GMat4[T]; b: GVec3[T]): GVec3[T] {.inline.}
```
-## **proc** quat
+## **proc** transpose
```nim
-proc quat(hpr: Vec3): Quat {.inline.}
+proc transpose[T](a: GMat3[T]): GMat3[T] {.inline.}
```
-## **proc** hrp
+## **proc** transpose
```nim
-proc hrp(q: Quat): Vec3
+proc transpose[T](a: GMat4[T]): GMat4[T] {.inline.}
```
-## **proc** dot
+## **proc** determinant
```nim
-proc dot(a: Quat; b: Quat): float32 {.inline.}
+proc determinant[T](a: GMat4[T]): T {.inline.}
```
-## **proc** nlerp
+## **proc** inverse
```nim
-proc nlerp(a: Quat; b: Quat; v: float32): Quat
+proc inverse[T](a: GMat3[T]): GMat3[T] {.inline.}
```
-## **proc** `$`
+## **proc** inverse
```nim
-proc `$`(a: Quat): string {.raises: [ValueError].}
+proc inverse[T](a: GMat4[T]): GMat4[T] {.inline.}
+```
+
+## **proc** scale
+
+
+```nim
+proc scale[T](v: GVec2[T]): GMat3[T] {.inline.}
+```
+
+## **proc** scale
+
+
+```nim
+proc scale[T](v: GVec3[T]): GMat4[T] {.inline.}
+```
+
+## **proc** translate
+
+
+```nim
+proc translate[T](v: GVec2[T]): GMat3[T] {.inline.}
+```
+
+## **proc** translate
+
+
+```nim
+proc translate[T](v: GVec3[T]): GMat4[T] {.inline.}
```
## **proc** rotate
```nim
-proc rotate(angle: float32; axis: Vec3): Mat4 {.inline.}
+proc rotate[T](angle: T): GMat3[T] {.inline.}
+```
+
+## **proc** hrp
+
+
+```nim
+proc hrp[T](m: GMat4[T]): GVec3[T] {.inline.}
+```
+
+## **proc** frustum
+
+
+```nim
+proc frustum[T](left, right, bottom, top, near, far: T): GMat4[T] {.inline.}
+```
+
+## **proc** perspective
+
+
+```nim
+proc perspective[T](fovy, aspect, near, far: T): GMat4[T] {.inline.}
+```
+
+## **proc** ortho
+
+
+```nim
+proc ortho[T](left, right, bottom, top, near, far: T): GMat4[T] {.inline.}
+```
+
+## **proc** lookAt
+
+
+```nim
+proc lookAt[T](eye, center: GVec3[T]; up = [T(0), 0, 1]): GMat4[T] {.inline.}
+```
+
+## **proc** angle
+
+Angle of a Vec2.
+
+```nim
+proc angle[T](a: GVec2[T]): T {.inline.}
+```
+
+## **proc** angle
+
+Angle between 2 Vec2.
+
+```nim
+proc angle[T](a, b: GVec2[T]): T {.inline.}
+```
+
+## **proc** angle
+
+Angle between 2 Vec3.
+
+```nim
+proc angle[T](a, b: GVec3[T]): T {.inline.}
+```
+
+## **type** Quat
+
+
+```nim
+Quat = GVec4[float32]
+```
+
+## **type** DQuat
+
+
+```nim
+DQuat = GVec4[float64]
+```
+
+## **proc** quat
+
+
+```nim
+proc quat(): Quat {.inline.}
+```
+
+## **proc** quat
+
+
+```nim
+proc quat(x`gensym41, y`gensym41, z`gensym41, w`gensym41: float32): Quat {. inline.}
+```
+
+## **proc** quat
+
+
+```nim
+proc quat(x`gensym41: float32): Quat {.inline.}
+```
+
+## **proc** quat
+
+
+```nim
+proc quat[T](x`gensym41: GVec4[T]): Quat {.inline.}
+```
+
+## **proc** dquat
+
+
+```nim
+proc dquat(): DQuat {.inline.}
+```
+
+## **proc** dquat
+
+
+```nim
+proc dquat(x`gensym42, y`gensym42, z`gensym42, w`gensym42: float64): DQuat {. inline.}
+```
+
+## **proc** dquat
+
+
+```nim
+proc dquat(x`gensym42: float64): DQuat {.inline.}
+```
+
+## **proc** dquat
+
+
+```nim
+proc dquat[T](x`gensym42: GVec4[T]): DQuat {.inline.}
+```
+
+## **proc** fromAxisAngle
+
+
+```nim
+proc fromAxisAngle[T](axis: GVec3[T]; angle: T): GVec4[T] {.inline.}
+```
+
+## **proc** toAxisAngle
+
+
+```nim
+proc toAxisAngle[T](q: GVec4[T]): (GVec3[T], T) {.inline.}
+```
+
+## **proc** orthogonal
+
+
+```nim
+proc orthogonal[T](v: GVec3[T]): GVec3[T] {.inline.}
+```
+
+## **proc** fromTwoVectors
+
+Return a quat that would take a and rotate it into b.
+
+```nim
+proc fromTwoVectors[T](a, b: GVec3[T]): GVec4[T] {.inline.}
+```
+
+## **proc** quat
+
+
+```nim
+proc quat[T](m: GMat4[T]): GVec4[T] {.inline.}
+```
+
+## **proc** mat4
+
+
+```nim
+proc mat4[T](q: GVec4[T]): GMat4[T] {.inline.}
+```
+
+## **proc** rotate
+
+
+```nim
+proc rotate[T](angle: T; axis: GVec3[T]): GMat4[T] {.inline.}
```
## **proc** rotateX
```nim
-proc rotateX(angle: float32): Mat4 {.inline.}
+proc rotateX[T](angle: T): GMat4[T] {.inline.}
```
## **proc** rotateY
```nim
-proc rotateY(angle: float32): Mat4 {.inline.}
+proc rotateY[T](angle: T): GMat4[T] {.inline.}
```
## **proc** rotateZ
```nim
-proc rotateZ(angle: float32): Mat4 {.inline.}
-```
-
-## **proc** scaleMat
-
-
-```nim
-proc scaleMat(scale: Vec3): Mat4 {.inline.}
-```
-
-## **proc** scaleMat
-
-
-```nim
-proc scaleMat(scale: float32): Mat4 {.inline.}
+proc rotateZ[T](angle: T): GMat4[T] {.inline.}
```
diff --git a/docs/banner.png b/docs/banner.png
new file mode 100644
index 0000000..8a111d6
Binary files /dev/null and b/docs/banner.png differ
diff --git a/src/vmath.nim b/src/vmath.nim
index 7f16ef8..4539625 100644
--- a/src/vmath.nim
+++ b/src/vmath.nim
@@ -1,32 +1,64 @@
-import hashes, math, random, strformat, strutils
+import math
export math
-proc `~=`*(a, b: float32): bool =
+type
+ GVec2*[T] = array[2, T]
+ GVec3*[T] = array[3, T]
+ GVec4*[T] = array[4, T]
+
+ BVec2* = GVec2[bool]
+ BVec3* = GVec3[bool]
+ BVec4* = GVec4[bool]
+
+ IVec2* = GVec2[int32]
+ IVec3* = GVec3[int32]
+ IVec4* = GVec4[int32]
+
+ UVec2* = GVec2[uint32]
+ UVec3* = GVec3[uint32]
+ UVec4* = GVec4[uint32]
+
+ Vec2* = GVec2[float32]
+ Vec3* = GVec3[float32]
+ Vec4* = GVec4[float32]
+
+ DVec2* = GVec2[float64]
+ DVec3* = GVec3[float64]
+ DVec4* = GVec4[float64]
+
+ GVec34[T] = GVec3[T] | GVec4[T]
+ GVec234[T] = GVec2[T] | GVec3[T] | GVec4[T]
+
+{.push inline.}
+when defined(release):
+ {.push noinit, checks: off.}
+
+proc `~=`*[T: SomeFloat](a, b: T): bool =
## Almost equal.
const epsilon = 0.000001
- abs(a - b) < epsilon
+ abs(a - b) <= epsilon
-proc between*(value, min, max: float32): bool {.inline.} =
+proc between*[T](value, min, max: T): bool =
## Returns true if value is between min and max or equal to them.
(value >= min) and (value <= max)
-proc sign*(v: float32): float32 {.inline.} =
+proc sign*[T](v: T): T =
## Returns the sign of a number, -1 or 1.
- if v >= 0: 1.0 else: -1.0
+ if v >= 0: 1 else: -1
-proc quantize*(v, n: float32): float32 {.inline.} =
- ## Makes v be multipe of n. Rounding to integer quantize by 1.0.
+proc quantize*[T: SomeFloat](v, n: T): T =
+ ## Makes v be multiple of n. Rounding to integer quantize by 1.0.
sign(v) * floor(abs(v) / n) * n
-proc lerp*(a, b, v: float32): float32 {.inline.} =
+proc lerp*[T: SomeFloat](a, b, v: T): T =
## Interpolates value between a and b.
## * 0 -> a
## * 1 -> b
## * 0.5 -> between a and b
a * (1.0 - v) + b * v
-proc fixAngle*(angle: float32): float32 =
+proc fixAngle*[T: SomeFloat](angle: T): T =
## Make angle be from -PI to PI radians.
var angle = angle
while angle > PI:
@@ -35,11 +67,11 @@ proc fixAngle*(angle: float32): float32 =
angle += PI * 2
angle
-proc angleBetween*(a, b: float32): float32 {.inline.} =
+proc angleBetween*[T: SomeFloat](a, b: T): T =
## Angle between angle a and angle b.
fixAngle(b - a)
-proc turnAngle*(a, b, speed: float32): float32 =
+proc turnAngle*[T: SomeFloat](a, b, speed: T): T =
## Move from angle a to angle b with step of v.
var
turn = fixAngle(b - a)
@@ -51,704 +83,530 @@ proc turnAngle*(a, b, speed: float32): float32 =
turn = -speed
a + turn
-type Vec2* = object
- ## 2D vector
- x*: float32
- y*: float32
+proc toRadians*[T: SomeFloat](deg: T): T =
+ return PI * deg / 180.0
-proc vec2*(x, y: float32): Vec2 {.inline.} =
- result.x = x
- result.y = y
+proc toDegrees*[T: SomeFloat](rad: T): T =
+ return fixAngle(180.0 * rad / PI)
-proc vec2*(v: float32): Vec2 {.inline.} =
- result.x = v
- result.y = v
+proc gvec2*[T](x, y: T): GVec2[T] =
+ [x, y]
-proc vec2*(a: Vec2): Vec2 {.inline.} =
- result.x = a.x
- result.y = a.y
+proc gvec3*[T](x, y, z: T): GVec3[T] =
+ [x, y, z]
-proc `~=`*(a, b: Vec2): bool =
+proc gvec4*[T](x, y, z, w: T): GVec4[T] =
+ [x, y, z, w]
+
+template genConstructor(lower, upper, typ: untyped) =
+ proc `lower 2`*(x, y: typ): `upper 2` = gvec2[typ](x, y)
+ proc `lower 3`*(x, y, z: typ): `upper 3` = gvec3[typ](x, y, z)
+ proc `lower 4`*(x, y, z, w: typ): `upper 4` = gvec4[typ](x, y, z, w)
+
+ proc `lower 2`*(x: typ): `upper 2` = gvec2[typ](x, x)
+ proc `lower 3`*(x: typ): `upper 3` = gvec3[typ](x, x, x)
+ proc `lower 4`*(x: typ): `upper 4` = gvec4[typ](x, x, x, x)
+
+ proc `lower 2`*[T](x: GVec2[T]): `upper 2` =
+ gvec2[typ](typ(x[0]), typ(x[1]))
+ proc `lower 3`*[T](x: GVec3[T]): `upper 3` =
+ gvec3[typ](typ(x[0]), typ(x[1]), typ(x[2]))
+ proc `lower 4`*[T](x: GVec4[T]): `upper 4` =
+ gvec4[typ](typ(x[0]), typ(x[1]), typ(x[2]), typ(x[3]))
+
+ proc `lower 3`*[T](x: GVec2[T]): `upper 3` =
+ gvec3[typ](typ(x[0]), typ(x[1]), 0)
+ proc `lower 4`*[T](x: GVec3[T]): `upper 4` =
+ gvec4[typ](typ(x[0]), typ(x[1]), typ(x[2]), 0)
+
+genConstructor(bvec, BVec, bool)
+genConstructor(ivec, IVec, int32)
+genConstructor(uvec, UVec, uint32)
+genConstructor(vec, Vec, float32)
+genConstructor(dvec, DVec, float64)
+
+proc x*[T](a: var GVec2[T]): var T = a[0]
+proc y*[T](a: var GVec2[T]): var T = a[1]
+
+proc x*[T](a: var GVec3[T]): var T = a[0]
+proc y*[T](a: var GVec3[T]): var T = a[1]
+proc z*[T](a: var GVec3[T]): var T = a[2]
+
+proc x*[T](a: var GVec4[T]): var T = a[0]
+proc y*[T](a: var GVec4[T]): var T = a[1]
+proc z*[T](a: var GVec4[T]): var T = a[2]
+proc w*[T](a: var GVec4[T]): var T = a[3]
+
+proc x*[T](a: GVec2[T]): T = a[0]
+proc x*[T](a: GVec3[T]): T = a[0]
+proc x*[T](a: GVec4[T]): T = a[0]
+
+proc y*[T](a: GVec2[T]): T = a[1]
+proc y*[T](a: GVec3[T]): T = a[1]
+proc y*[T](a: GVec4[T]): T = a[1]
+
+proc z*[T](a: GVec2[T]): T = {.error: "using .w on a Vec2".}
+proc z*[T](a: GVec3[T]): T = a[2]
+proc z*[T](a: GVec4[T]): T = a[2]
+
+proc w*[T](a: GVec2[T]): T = {.error: "using .w on a Vec2".}
+proc w*[T](a: GVec3[T]): T = {.error: "using .w on a Vec3".}
+proc w*[T](a: GVec4[T]): T = a[3]
+
+proc `x=`*[T](a: var GVec234[T], value: T) = a[0] = value
+proc `y=`*[T](a: var GVec234[T], value: T) = a[1] = value
+proc `z=`*[T](a: var GVec34[T], value: T) = a[2] = value
+proc `w=`*[T](a: var GVec4[T], value: T) = a[3] = value
+
+proc xy*[T](a: GVec234[T]): GVec2[T] = [a.x, a.y]
+proc xz*[T](a: GVec234[T]): GVec2[T] = [a.x, a.z]
+proc yx*[T](a: GVec234[T]): GVec2[T] = [a.y, a.x]
+proc yz*[T](a: GVec234[T]): GVec2[T] = [a.y, a.z]
+proc zx*[T](a: GVec234[T]): GVec2[T] = [a.z, a.x]
+proc zy*[T](a: GVec234[T]): GVec2[T] = [a.z, a.y]
+
+proc xxx*[T](a: GVec34[T]): GVec3[T] = [a.x, a.x, a.x]
+proc xxy*[T](a: GVec34[T]): GVec3[T] = [a.x, a.x, a.y]
+proc xxz*[T](a: GVec34[T]): GVec3[T] = [a.x, a.x, a.z]
+proc xyx*[T](a: GVec34[T]): GVec3[T] = [a.x, a.y, a.x]
+proc xyy*[T](a: GVec34[T]): GVec3[T] = [a.x, a.y, a.y]
+proc xyz*[T](a: GVec34[T]): GVec3[T] = [a.x, a.y, a.z]
+proc xzx*[T](a: GVec34[T]): GVec3[T] = [a.x, a.z, a.x]
+proc xzy*[T](a: GVec34[T]): GVec3[T] = [a.x, a.z, a.y]
+proc xzz*[T](a: GVec34[T]): GVec3[T] = [a.x, a.z, a.z]
+proc yxx*[T](a: GVec34[T]): GVec3[T] = [a.y, a.x, a.x]
+proc yxy*[T](a: GVec34[T]): GVec3[T] = [a.y, a.x, a.y]
+proc yxz*[T](a: GVec34[T]): GVec3[T] = [a.y, a.x, a.z]
+proc yyx*[T](a: GVec34[T]): GVec3[T] = [a.y, a.y, a.x]
+proc yyy*[T](a: GVec34[T]): GVec3[T] = [a.y, a.y, a.y]
+proc yyz*[T](a: GVec34[T]): GVec3[T] = [a.y, a.y, a.z]
+proc yzx*[T](a: GVec34[T]): GVec3[T] = [a.y, a.z, a.x]
+proc yzy*[T](a: GVec34[T]): GVec3[T] = [a.y, a.z, a.y]
+proc yzz*[T](a: GVec34[T]): GVec3[T] = [a.y, a.z, a.z]
+proc zxx*[T](a: GVec34[T]): GVec3[T] = [a.z, a.x, a.x]
+proc zxy*[T](a: GVec34[T]): GVec3[T] = [a.z, a.x, a.y]
+proc zxz*[T](a: GVec34[T]): GVec3[T] = [a.z, a.x, a.z]
+proc zyx*[T](a: GVec34[T]): GVec3[T] = [a.z, a.y, a.x]
+proc zyy*[T](a: GVec34[T]): GVec3[T] = [a.z, a.y, a.y]
+proc zyz*[T](a: GVec34[T]): GVec3[T] = [a.z, a.y, a.z]
+proc zzx*[T](a: GVec34[T]): GVec3[T] = [a.z, a.z, a.x]
+proc zzy*[T](a: GVec34[T]): GVec3[T] = [a.z, a.z, a.y]
+proc zzz*[T](a: GVec34[T]): GVec3[T] = [a.z, a.z, a.z]
+
+template genOp(op: untyped) =
+ proc op*[T](a, b: GVec2[T]): GVec2[T] =
+ [
+ op(a[0], b[0]),
+ op(a[1], b[1])
+ ]
+
+ proc op*[T](a, b: GVec3[T]): GVec3[T] =
+ [
+ op(a[0], b[0]),
+ op(a[1], b[1]),
+ op(a[2], b[2])
+ ]
+
+ proc op*[T](a, b: GVec4[T]): GVec4[T] =
+ [
+ op(a[0], b[0]),
+ op(a[1], b[1]),
+ op(a[2], b[2]),
+ op(a[3], b[3])
+ ]
+
+ proc op*[T](a: GVec2[T], b: T): GVec2[T] =
+ [
+ op(a[0], b),
+ op(a[1], b)
+ ]
+
+ proc op*[T](a: GVec3[T], b: T): GVec3[T] =
+ [
+ op(a[0], b),
+ op(a[1], b),
+ op(a[2], b)
+ ]
+
+ proc op*[T](a: GVec4[T], b: T): GVec4[T] =
+ [
+ op(a[0], b),
+ op(a[1], b),
+ op(a[2], b),
+ op(a[3], b)
+ ]
+
+ proc op*[T](a: T, b: GVec2[T]): GVec2[T] =
+ [
+ op(a, b[0]),
+ op(a, b[1])
+ ]
+
+ proc op*[T](a: T, b: GVec3[T]): GVec3[T] =
+ [
+ op(a, b[0]),
+ op(a, b[1]),
+ op(a, b[2])
+ ]
+
+ proc op*[T](a: T, b: GVec4[T]): GVec4[T] =
+ [
+ op(a, b[0]),
+ op(a, b[1]),
+ op(a, b[2]),
+ op(a, b[3])
+ ]
+
+genOp(`+`)
+genOp(`-`)
+genOp(`*`)
+genOp(`/`)
+genOp(`mod`)
+genOp(`div`)
+
+template genEqOp(op: untyped) =
+ proc op*[T](a: var GVec2[T], b: GVec2[T]) =
+ op(a[0], b[0])
+ op(a[1], b[1])
+
+ proc op*[T](a: var GVec3[T], b: GVec3[T]) =
+ op(a[0], b[0])
+ op(a[1], b[1])
+ op(a[2], b[2])
+
+ proc op*[T](a: var GVec4[T], b: GVec4[T]) =
+ op(a[0], b[0])
+ op(a[1], b[1])
+ op(a[2], b[2])
+ op(a[3], b[3])
+
+ proc op*[T](a: var GVec2[T], b: T) =
+ op(a[0], b)
+ op(a[1], b)
+
+ proc op*[T](a: var GVec3[T], b: T) =
+ op(a[0], b)
+ op(a[1], b)
+ op(a[2], b)
+
+ proc op*[T](a: var GVec4[T], b: T) =
+ op(a[0], b)
+ op(a[1], b)
+ op(a[2], b)
+ op(a[3], b)
+
+genEqOp(`+=`)
+genEqOp(`-=`)
+genEqOp(`*=`)
+genEqOp(`/=`)
+
+template genMathFn(fn: untyped) =
+ proc fn*[T](v: GVec2[T]): GVec2[T] =
+ [
+ fn(v[0]),
+ fn(v[1])
+ ]
+
+ proc fn*[T](v: GVec3[T]): GVec3[T] =
+ [
+ fn(v[0]),
+ fn(v[1]),
+ fn(v[2])
+ ]
+
+ proc fn*[T](v: GVec4[T]): GVec4[T] =
+ [
+ fn(v[0]),
+ fn(v[1]),
+ fn(v[2]),
+ fn(v[3])
+ ]
+
+genMathFn(`-`)
+genMathFn(sin)
+genMathFn(cos)
+genMathFn(tan)
+genMathFn(arcsin)
+genMathFn(arccos)
+genMathFn(arctan)
+genMathFn(sinh)
+genMathFn(cosh)
+genMathFn(tanh)
+genMathFn(exp2)
+genMathFn(inversesqrt)
+genMathFn(exp)
+genMathFn(ln)
+genMathFn(log2)
+genMathFn(sqrt)
+genMathFn(floor)
+genMathFn(ciel)
+genMathFn(abs)
+
+proc `~=`*[T](a, b: GVec2[T]): bool =
+ ## Almost equal.
a.x ~= b.x and a.y ~= b.y
-proc `+`*(a, b: Vec2): Vec2 {.inline.} =
- result.x = a.x + b.x
- result.y = a.y + b.y
-
-proc `-`*(a, b: Vec2): Vec2 {.inline.} =
- result.x = a.x - b.x
- result.y = a.y - b.y
-
-proc `*`*(a: Vec2, b: float32): Vec2 {.inline.} =
- result.x = a.x * b
- result.y = a.y * b
-
-proc `*`*(a: float32, b: Vec2): Vec2 {.inline.} =
- b * a
-
-proc `/`*(a: Vec2, b: float32): Vec2 {.inline.} =
- result.x = a.x / b
- result.y = a.y / b
-
-proc `+=`*(a: var Vec2, b: Vec2) {.inline.} =
- a.x += b.x
- a.y += b.y
-
-proc `-=`*(a: var Vec2, b: Vec2) {.inline.} =
- a.x -= b.x
- a.y -= b.y
-
-proc `*=`*(a: var Vec2, b: float32) {.inline.} =
- a.x *= b
- a.y *= b
-
-proc `/=`*(a: var Vec2, b: float32) {.inline.} =
- a.x /= b
- a.y /= b
-
-proc zero*(a: var Vec2) {.inline.} =
- a.x = 0
- a.y = 0
-
-proc `-`*(a: Vec2): Vec2 {.inline.} =
- result.x = -a.x
- result.y = -a.y
-
-proc hash*(a: Vec2): Hash {.inline.} =
- hash((a.x, a.y))
-
-proc lengthSq*(a: Vec2): float32 {.inline.} =
- a.x * a.x + a.y * a.y
-
-proc length*(a: Vec2): float32 {.inline.} =
- sqrt(a.lengthSq)
-
-proc `length=`*(a: var Vec2, b: float32) {.inline.} =
- a *= b / a.length
-
-proc normalize*(a: Vec2): Vec2 {.inline.} =
- a / a.length
-
-proc floor*(a: Vec2): Vec2 {.inline.} =
- vec2(floor(a.x), floor(a.y))
-
-proc round*(a: Vec2): Vec2 {.inline.} =
- vec2(round(a.x), round(a.y))
-
-proc ceil*(a: Vec2): Vec2 {.inline.} =
- vec2(ceil(a.x), ceil(a.y))
-
-proc dot*(a, b: Vec2): float32 {.inline.} =
- a.x * b.x + a.y * b.y
-
-proc dir*(at, to: Vec2): Vec2 {.inline.} =
- (at - to).normalize()
-
-proc dir*(th: float32): Vec2 {.inline.} =
- vec2(cos(th), sin(th))
-
-proc dist*(at, to: Vec2): float32 {.inline.} =
- (at - to).length
-
-proc distSq*(at, to: Vec2): float32 {.inline.} =
- (at - to).lengthSq
-
-proc lerp*(a, b: Vec2, v: float32): Vec2 {.inline.} =
- a * (1.0 - v) + b * v
-
-proc quantize*(v: Vec2, n: float32): Vec2 {.inline.} =
- result.x = sign(v.x) * floor(abs(v.x) / n) * n
- result.y = sign(v.y) * floor(abs(v.y) / n) * n
-
-proc `[]`*(a: Vec2, i: int): float32 =
- case i
- of 0: a.x
- of 1: a.y
- else: raise newException(IndexDefect, "Index not in 0 .. 1")
-
-proc `[]=`*(a: var Vec2, i: int, b: float32) =
- case i
- of 0: a.x = b
- of 1: a.y = b
- else: raise newException(IndexDefect, "Index not in 0 .. 1")
-
-proc randVec2*(r: var Rand): Vec2 =
- let a = r.rand(PI * 2)
- let v = r.rand(1.0)
- vec2(cos(a) * v, sin(a) * v)
-
-proc `$`*(a: Vec2): string =
- &"({a.x:.7f}, {a.y:.7f})"
-
-proc angle*(a: Vec2): float32 {.inline.} =
- ## Angle of a Vec2.
- arctan2(a.y, a.x)
-
-proc angleBetween*(a: Vec2, b: Vec2): float32 {.inline.} =
- ## Angle between 2 Vec2.
- fixAngle(arctan2(a.y - b.y, a.x - b.x))
-
-type Vec3* = object
- ## 3D vector
- x*: float32
- y*: float32
- z*: float32
-
-proc vec3*(x, y, z: float32): Vec3 {.inline.} =
- result.x = x
- result.y = y
- result.z = z
-
-proc vec3*(v: float32): Vec3 {.inline.} =
- result.x = v
- result.y = v
- result.z = v
-
-proc vec3*(a: Vec3): Vec3 {.inline.} =
- result.x = a.x
- result.y = a.y
- result.z = a.z
-
-const X_DIR* = vec3(1.0, 0.0, 0.0)
-const Y_DIR* = vec3(0.0, 1.0, 0.0)
-const Z_DIR* = vec3(0.0, 0.0, 1.0)
-
-proc `~=`*(a, b: Vec3): bool =
+proc `~=`*[T](a, b: GVec3[T]): bool =
+ ## Almost equal.
a.x ~= b.x and a.y ~= b.y and a.z ~= b.z
-proc `+`*(a, b: Vec3): Vec3 {.inline.} =
- result.x = a.x + b.x
- result.y = a.y + b.y
- result.z = a.z + b.z
-
-proc `-`*(a, b: Vec3): Vec3 {.inline.} =
- result.x = a.x - b.x
- result.y = a.y - b.y
- result.z = a.z - b.z
-
-proc `-`*(a: Vec3): Vec3 {.inline.} =
- result.x = -a.x
- result.y = -a.y
- result.z = -a.z
-
-proc `*`*(a: Vec3, b: float32): Vec3 {.inline.} =
- result.x = a.x * b
- result.y = a.y * b
- result.z = a.z * b
-
-proc `*`*(a: float32, b: Vec3): Vec3 {.inline.} =
- b * a
-
-proc `/`*(a: Vec3, b: float32): Vec3 {.inline.} =
- result.x = a.x / b
- result.y = a.y / b
- result.z = a.z / b
-
-proc `/`*(a: float32, b: Vec3): Vec3 {.inline.} =
- result.x = a / b.x
- result.y = a / b.y
- result.z = a / b.z
-
-proc `+=`*(a: var Vec3, b: Vec3) {.inline.} =
- a.x += b.x
- a.y += b.y
- a.z += b.z
-
-proc `-=`*(a: var Vec3, b: Vec3) {.inline.} =
- a.x -= b.x
- a.y -= b.y
- a.z -= b.z
-
-proc `*=`*(a: var Vec3, b: float32) {.inline.} =
- a.x *= b
- a.y *= b
- a.z *= b
-
-proc `/=`*(a: var Vec3, b: float32) {.inline.} =
- a.x /= b
- a.y /= b
- a.z /= b
-
-proc zero*(a: var Vec3) {.inline.} =
- a.x = 0
- a.y = 0
- a.z = 0
-
-proc `-`*(a: var Vec3): Vec3 {.inline.} =
- result.x = -a.x
- result.y = -a.y
- result.z = -a.z
-
-proc hash*(a: Vec3): Hash {.inline.} =
- hash((a.x, a.y, a.z))
-
-proc lengthSq*(a: Vec3): float32 {.inline.} =
- a.x * a.x + a.y * a.y + a.z * a.z
-
-proc length*(a: Vec3): float32 {.inline.} =
- sqrt(a.lengthSq)
-
-proc `length=`*(a: var Vec3, b: float32) {.inline.} =
- a *= b / a.length
-
-proc floor*(a: Vec3): Vec3 {.inline.} =
- vec3(floor(a.x), floor(a.y), floor(a.z))
-
-proc round*(a: Vec3): Vec3 {.inline.} =
- vec3(round(a.x), round(a.y), round(a.z))
-
-proc ceil*(a: Vec3): Vec3 {.inline.} =
- vec3(ceil(a.x), ceil(a.y), ceil(a.z))
-
-proc normalize*(a: Vec3): Vec3 {.inline.} =
- a / sqrt(a.x * a.x + a.y * a.y + a.z * a.z)
-
-proc cross*(a, b: Vec3): Vec3 {.inline.} =
- result.x = a.y * b.z - a.z * b.y
- result.y = a.z * b.x - a.x * b.z
- result.z = a.x * b.y - a.y * b.x
-
-proc computeNormal*(a, b, c: Vec3): Vec3 =
- cross(c - b, b - a).normalize()
-
-proc dot*(a, b: Vec3): float32 {.inline.} =
- a.x * b.x + a.y * b.y + a.z * b.z
-
-proc dir*(at, to: Vec3): Vec3 {.inline.} =
- (at - to).normalize()
-
-proc dist*(at, to: Vec3): float32 {.inline.} =
- (at - to).length
-
-proc distSq*(at, to: Vec3): float32 {.inline.} =
- (at - to).lengthSq
-
-proc lerp*(a, b: Vec3, v: float32): Vec3 {.inline.} =
- a * (1.0 - v) + b * v
-
-proc quantize*(v: Vec3, n: float32): Vec3 =
- result.x = sign(v.x) * floor(abs(v.x) / n) * n
- result.y = sign(v.y) * floor(abs(v.y) / n) * n
- result.z = sign(v.z) * floor(abs(v.z) / n) * n
-
-proc angleBetween*(a, b: Vec3): float32 =
- var dot = dot(a, b)
- dot = dot / (a.length * b.length)
- arccos(dot)
-
-proc `[]`*(a: Vec3, i: int): float32 =
- case i
- of 0: a.x
- of 1: a.y
- of 2: a.z
- else: raise newException(IndexDefect, "Index not in 0 .. 2")
-
-proc `[]=`*(a: var Vec3, i: int, b: float32) =
- case i
- of 0: a.x = b
- of 1: a.y = b
- of 2: a.z = b
- else: raise newException(IndexDefect, "Index not in 0 .. 2")
-
-proc xy*(a: Vec3): Vec2 {.inline.} = vec2(a.x, a.y)
-proc xz*(a: Vec3): Vec2 {.inline.} = vec2(a.x, a.z)
-proc yx*(a: Vec3): Vec2 {.inline.} = vec2(a.y, a.x)
-proc yz*(a: Vec3): Vec2 {.inline.} = vec2(a.y, a.z)
-proc zx*(a: Vec3): Vec2 {.inline.} = vec2(a.z, a.x)
-proc zy*(a: Vec3): Vec2 {.inline.} = vec2(a.z, a.y)
-
-proc xxx*(a: Vec3): Vec3 {.inline.} = vec3(a.x, a.x, a.x)
-proc xxy*(a: Vec3): Vec3 {.inline.} = vec3(a.x, a.x, a.y)
-proc xxz*(a: Vec3): Vec3 {.inline.} = vec3(a.x, a.x, a.z)
-proc xyx*(a: Vec3): Vec3 {.inline.} = vec3(a.x, a.y, a.x)
-proc xyy*(a: Vec3): Vec3 {.inline.} = vec3(a.x, a.y, a.y)
-proc xyz*(a: Vec3): Vec3 {.inline.} = vec3(a.x, a.y, a.z)
-proc xzx*(a: Vec3): Vec3 {.inline.} = vec3(a.x, a.z, a.x)
-proc xzy*(a: Vec3): Vec3 {.inline.} = vec3(a.x, a.z, a.y)
-proc xzz*(a: Vec3): Vec3 {.inline.} = vec3(a.x, a.z, a.z)
-proc yxx*(a: Vec3): Vec3 {.inline.} = vec3(a.y, a.x, a.x)
-proc yxy*(a: Vec3): Vec3 {.inline.} = vec3(a.y, a.x, a.y)
-proc yxz*(a: Vec3): Vec3 {.inline.} = vec3(a.y, a.x, a.z)
-proc yyx*(a: Vec3): Vec3 {.inline.} = vec3(a.y, a.y, a.x)
-proc yyy*(a: Vec3): Vec3 {.inline.} = vec3(a.y, a.y, a.y)
-proc yyz*(a: Vec3): Vec3 {.inline.} = vec3(a.y, a.y, a.z)
-proc yzx*(a: Vec3): Vec3 {.inline.} = vec3(a.y, a.z, a.x)
-proc yzy*(a: Vec3): Vec3 {.inline.} = vec3(a.y, a.z, a.y)
-proc yzz*(a: Vec3): Vec3 {.inline.} = vec3(a.y, a.z, a.z)
-proc zxx*(a: Vec3): Vec3 {.inline.} = vec3(a.z, a.x, a.x)
-proc zxy*(a: Vec3): Vec3 {.inline.} = vec3(a.z, a.x, a.y)
-proc zxz*(a: Vec3): Vec3 {.inline.} = vec3(a.z, a.x, a.z)
-proc zyx*(a: Vec3): Vec3 {.inline.} = vec3(a.z, a.y, a.x)
-proc zyy*(a: Vec3): Vec3 {.inline.} = vec3(a.z, a.y, a.y)
-proc zyz*(a: Vec3): Vec3 {.inline.} = vec3(a.z, a.y, a.z)
-proc zzx*(a: Vec3): Vec3 {.inline.} = vec3(a.z, a.z, a.x)
-proc zzy*(a: Vec3): Vec3 {.inline.} = vec3(a.z, a.z, a.y)
-proc zzz*(a: Vec3): Vec3 {.inline.} = vec3(a.z, a.z, a.z)
-
-proc randVec3*(r: var Rand): Vec3 =
- ## Generates a random unit vector based on
- ## http://mathworld.wolfram.com/SpherePointPicking.html
- let
- u = r.rand(0.0 .. 1.0)
- v = r.rand(0.0 .. 1.0)
- th = 2 * PI * u
- ph = arccos(2 * v - 1)
- vec3(
- cos(th) * sin(ph),
- sin(th) * sin(ph),
- cos(ph)
- )
-
-proc `$`*(a: Vec3): string =
- &"({a.x:.8f}, {a.y:.8f}, {a.z:.8f})"
-
-type Vec4* = object
- ## 4D Vector.
- x*: float32
- y*: float32
- z*: float32
- w*: float32
-
-proc vec4*(x, y, z, w: float32): Vec4 {.inline.} =
- result.x = x
- result.y = y
- result.z = z
- result.w = w
-
-proc vec4*(v: float32): Vec4 {.inline.} =
- result.x = v
- result.y = v
- result.z = v
- result.w = v
-
-proc `~=`*(a, b: Vec4): bool =
+proc `~=`*[T](a, b: GVec4[T]): bool =
+ ## Almost equal.
a.x ~= b.x and a.y ~= b.y and a.z ~= b.z and a.w ~= b.w
-proc `+`*(a, b: Vec4): Vec4 {.inline.} =
- result.x = a.x + b.x
- result.y = a.y + b.y
- result.z = a.z + b.z
- result.w = a.w + b.w
+proc length*[T](a: GVec2[T]): T =
+ sqrt(a.x*a.x + a.y*a.y)
-proc `-`*(a, b: Vec4): Vec4 {.inline.} =
- result.x = a.x - b.x
- result.y = a.y - b.y
- result.z = a.z - b.z
- result.w = a.w - b.w
+proc length*[T](a: GVec3[T]): T =
+ sqrt(a.x*a.x + a.y*a.y + a.z*a.z)
-proc `-`*(a: Vec4): Vec4 {.inline.} =
- result.x = -a.x
- result.y = -a.y
- result.z = -a.z
- result.w = -a.w
+proc length*[T](a: GVec4[T]): T =
+ sqrt(a.x*a.x + a.y*a.y + a.z*a.z + a.w*a.w)
-proc `*`*(a: Vec4, b: float32): Vec4 {.inline.} =
- result.x = a.x * b
- result.y = a.y * b
- result.z = a.z * b
- result.w = a.w * b
+proc lengthSq*[T](a: GVec2[T]): T =
+ a.x*a.x + a.y*a.y
-proc `*`*(a: float32, b: Vec4): Vec4 {.inline.} =
- b * a
+proc lengthSq*[T](a: GVec3[T]): T =
+ a.x*a.x + a.y*a.y + a.z*a.z
-proc `/`*(a: Vec4, b: float32): Vec4 {.inline.} =
- result.x = a.x / b
- result.y = a.y / b
- result.z = a.z / b
- result.w = a.w / b
+proc lengthSq*[T](a: GVec4[T]): T =
+ a.x*a.x + a.y*a.y + a.z*a.z + a.w*a.w
-proc `/`*(a: float32, b: Vec4): Vec4 {.inline.} =
- result.x = a / b.x
- result.y = a / b.y
- result.z = a / b.z
- result.w = a / b.w
+proc normalize*[T](a: GVec234[T]): type(a) =
+ a / a.length
-proc `+=`*(a: var Vec4, b: Vec4) {.inline.} =
- a.x += b.x
- a.y += b.y
- a.z += b.z
- a.w += b.w
-
-proc `-=`*(a: var Vec4, b: Vec4) {.inline.} =
- a.x -= b.x
- a.y -= b.y
- a.z -= b.z
- a.w -= b.w
-
-proc `*=`*(a: var Vec4, b: float32) {.inline.} =
- a.x *= b
- a.y *= b
- a.z *= b
- a.w *= b
-
-proc `/=`*(a: var Vec4, b: float32) {.inline.} =
- a.x /= b
- a.y /= b
- a.z /= b
- a.w /= b
-
-proc zero*(a: var Vec4) {.inline.} =
- a.x = 0
- a.y = 0
- a.z = 0
- a.w = 0
-
-proc hash*(a: Vec4): Hash {.inline.} =
- hash((a.x, a.y, a.z, a.w))
-
-proc floor*(a: Vec4): Vec4 {.inline.} =
- vec4(floor(a.x), floor(a.y), floor(a.z), floor(a.w))
-
-proc round*(a: Vec4): Vec4 {.inline.} =
- vec4(round(a.x), round(a.y), round(a.z), round(a.w))
-
-proc ceil*(a: Vec4): Vec4 {.inline.} =
- vec4(ceil(a.x), ceil(a.y), ceil(a.z), ceil(a.w))
-
-proc `[]`*(a: Vec4, i: int): float32 =
- case i
- of 0: a.x
- of 1: a.y
- of 2: a.z
- of 3: a.w
- else: raise newException(IndexDefect, "Index not in 0 .. 3")
-
-proc `[]=`*(a: var Vec4, i: int, b: float32) =
- case i
- of 0: a.x = b
- of 1: a.y = b
- of 2: a.z = b
- of 3: a.w = b
- else: raise newException(IndexDefect, "Index not in 0 .. 3")
-
-proc lerp*(a: Vec4, b: Vec4, v: float32): Vec4 {.inline.} =
+proc lerp*[T: SomeFloat](a, b: GVec234[T], v: T): type(a) =
a * (1.0 - v) + b * v
-proc xyz*(a: Vec4): Vec3 {.inline.} =
- vec3(a.x, a.y, a.z)
+proc dot*[T](a, b: GVec2[T]): T =
+ a.x * b.x + a.y * b.y
-proc `$`*(a: Vec4): string =
- &"({a.x:.8f}, {a.y:.8f}, {a.z:.8f}, {a.w:.8f})"
+proc dot*[T](a, b: GVec3[T]): T =
+ a.x * b.x + a.y * b.y + a.z * b.z
-proc vec3*(a: Vec2, z = 0.0): Vec3 {.inline.} =
- vec3(a.x, a.y, z)
+proc dot*[T](a, b: GVec4[T]): T =
+ a.x * b.x + a.y * b.y + a.z * b.z + a.w * b.w
-proc vec4*(a: Vec3, w = 0.0): Vec4 {.inline.} =
- vec4(a.x, a.y, a.z, w)
-
-proc vec4*(a: Vec2, z = 0.0, w = 0.0): Vec4 {.inline.} =
- vec4(a.x, a.y, z, w)
-
-type Mat3* = array[9, float32] ## 3x3 Matrix
-
-proc `[]`*(a: Mat3, i, j: int): float32 {.inline.} = a[i * 3 + j]
-proc `[]=`*(a: var Mat3, i, j: int, v: float32) {.inline.} = a[i * 3 + j] = v
-
-proc mat3*(a, b, c, d, e, f, g, h, i: float32): Mat3 {.inline.} =
+proc cross*[T](a, b: GVec3[T]): GVec3[T] =
[
- a, b, c,
- d, e, f,
- g, h, i
+ a.y * b.z - a.z * b.y,
+ a.z * b.x - a.x * b.z,
+ a.x * b.y - a.y * b.x
]
-proc mat3*(a: Mat3): Mat3 {.inline.} =
- a
+proc dist*[T](at, to: GVec234[T]): T =
+ (at - to).length
-proc `~=`*(a: Mat3, b: Mat3): bool =
- for i in 0 .. 8:
- if not(a[i] ~= b[i]):
- return false
- true
+proc distSq*[T](at, to: GVec234[T]): T =
+ (at - to).lengthSq
-proc identity*(a: var Mat3) {.inline.} =
- a = [
- 1.float32, 0, 0,
- 0, 1, 0,
- 0, 0, 1
- ]
+proc dir*[T](at, to: GVec234[T]): type(to) =
+ (at - to).normalize
-proc mat3*(): Mat3 {.inline.} =
- result.identity()
-
-proc transpose*(a: Mat3): Mat3 {.inline.} =
+proc dir*[T](angle: T): GVec2[T] =
[
- a[0, 0], a[1, 0], a[2, 0],
- a[0, 1], a[1, 1], a[2, 1],
- a[0, 2], a[1, 2], a[2, 2]
+ cos(angle),
+ sin(angle),
]
-proc `$`*(a: Mat3): string =
- &"""[{a[0]:.7f}, {a[1]:.7f}, {a[2]:.7f},
-{a[3]:.7f}, {a[4]:.7f}, {a[5]:.7f},
-{a[6]:.7f}, {a[7]:.7f}, {a[8]:.7f}]"""
+type
+ GMat2*[T] = array[2, GVec2[T]]
+ GMat3*[T] = array[3, GVec3[T]]
+ GMat4*[T] = array[4, GVec4[T]]
-proc `*`*(a, b: Mat3): Mat3 =
+ Mat2* = GMat2[float32]
+ Mat3* = GMat3[float32]
+ Mat4* = GMat4[float32]
+
+ DMat2* = GMat2[float64]
+ DMat3* = GMat3[float64]
+ DMat4* = GMat4[float64]
+
+ GMat234[T] = GMat2[T] | GMat3[T] | GMat4[T]
+ GMat34[T] = GMat3[T] | GMat4[T]
+
+template genMatConstructor(lower, upper, T: untyped) =
+ proc `lower 2`*(a, b, c, d: T): `upper 2` =
+ [[a, b], [c, d]]
+ proc `lower 3`*(a, b, c, d, e, f, g, h, i: T): `upper 3` =
+ [[T(a), b, c], [d, e, f], [g, h, i]]
+ proc `lower 4`*(
+ a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p: T
+ ): `upper 4` =
+ [[T(a), b, c, d], [e, f, g, h], [i, j, k, l], [m, n, o, p]]
+
+ proc `lower 2`*(a, b: GVec2[T]): `upper 2` = [a, b]
+ proc `lower 3`*(a, b, c: GVec3[T]): `upper 3` = [a, b, c]
+ proc `lower 4`*(a, b, c, d: GVec4[T]): `upper 4` = [a, b, c, d]
+
+ proc `lower 2`*(m: GMat3[T]): `upper 2` = [m[0].xy, m[1].xy]
+ proc `lower 3`*(m: GMat4[T]): `upper 3` = [m[0].xyz, m[1].xyz, [T(0), 0, 1]]
+
+ proc `lower 3`*(m: GMat2[T]): `upper 3` =
+ [
+ [m[0][0], m[0][1], 0],
+ [m[1][0], m[1][1], 0],
+ [T(0), 0, 1]
+ ]
+
+ proc `lower 4`*(m: GMat3[T]): `upper 4` =
+ [
+ [m[0][0], m[0][1], m[0][2], 0],
+ [m[1][0], m[1][1], m[1][2], 0],
+ [T(0), 0, 1, 0],
+ [m[2][0], m[2][1], m[2][2], 1]
+ ]
+
+ proc `lower 2`*(): `upper 2` =
+ [
+ [T(1), 0],
+ [T(0), 1]
+ ]
+ proc `lower 3`*(): `upper 3` =
+ [
+ [T(1), 0, 0],
+ [T(0), 1, 0],
+ [T(0), 0, 1]
+ ]
+ proc `lower 4`*(): `upper 4` =
+ [
+ [T(1), 0, 0, 0],
+ [T(0), 1, 0, 0],
+ [T(0), 0, 1, 0],
+ [T(0), 0, 0, 1]
+ ]
+
+genMatConstructor(mat, Mat, float32)
+genMatConstructor(dmat, DMat, float64)
+
+proc `[]`*[T](a: GMat234[T], i, j: int): T = a[i][j]
+proc `[]=`*[T](a: var GMat234[T], i, j: int, v: T) = a[i][j] = v
+
+proc `~=`*[T](a, b: GMat2[T]): bool =
+ a[0] ~= b[0] and a[1] ~= b[1]
+
+proc `~=`*[T](a, b: GMat3[T]): bool =
+ a[0] ~= b[0] and a[1] ~= b[1] and a[2] ~= b[2]
+
+proc `~=`*[T](a, b: GMat4[T]): bool =
+ a[0] ~= b[0] and a[1] ~= b[1] and a[2] ~= b[2] and a[3] ~= b[3]
+
+proc `*`*[T](a, b: GMat3[T]): GMat3[T] =
result[0, 0] = b[0, 0] * a[0, 0] + b[0, 1] * a[1, 0] + b[0, 2] * a[2, 0]
result[0, 1] = b[0, 0] * a[0, 1] + b[0, 1] * a[1, 1] + b[0, 2] * a[2, 1]
result[0, 2] = b[0, 0] * a[0, 2] + b[0, 1] * a[1, 2] + b[0, 2] * a[2, 2]
+
result[1, 0] = b[1, 0] * a[0, 0] + b[1, 1] * a[1, 0] + b[1, 2] * a[2, 0]
result[1, 1] = b[1, 0] * a[0, 1] + b[1, 1] * a[1, 1] + b[1, 2] * a[2, 1]
result[1, 2] = b[1, 0] * a[0, 2] + b[1, 1] * a[1, 2] + b[1, 2] * a[2, 2]
+
result[2, 0] = b[2, 0] * a[0, 0] + b[2, 1] * a[1, 0] + b[2, 2] * a[2, 0]
result[2, 1] = b[2, 0] * a[0, 1] + b[2, 1] * a[1, 1] + b[2, 2] * a[2, 1]
result[2, 2] = b[2, 0] * a[0, 2] + b[2, 1] * a[1, 2] + b[2, 2] * a[2, 2]
-proc scale*(a: Mat3, v: Vec2): Mat3 {.inline.} =
+proc `*`*[T](a: GMat3[T], b: GVec2[T]): GVec2[T] =
[
- v.x * a[0], v.x * a[1], v.x * a[2],
- v.y * a[3], v.y * a[4], v.y * a[5],
- a[6], a[7], a[8]
+ a[0, 0] * b.x + a[1, 0] * b.y + a[2, 0],
+ a[0, 1] * b.x + a[1, 1] * b.y + a[2, 1]
]
-proc scale*(a: Mat3, v: Vec3): Mat3 {.inline.} =
- [
- v.x * a[0], v.x * a[1], v.x * a[2],
- v.y * a[3], v.y * a[4], v.y * a[5],
- v.z * a[6], v.z * a[7], v.z * a[8]
- ]
-
-proc translate*(v: Vec2): Mat3 {.inline.} =
- [
- 1.float32, 0, 0,
- 0, 1, 0,
- v.x, v.y, 1
- ]
-
-proc scale*(v: Vec2): Mat3 {.inline.} =
- [
- v.x, 0, 0,
- 0, v.y, 0,
- 0, 0, 1
- ]
-
-proc rotationMat3*(angle: float32): Mat3 {.inline.} =
- # Create a matrix from an angle.
+proc `*`*[T](a, b: GMat4[T]): GMat4[T] =
let
- sin = sin(angle)
- cos = cos(angle)
- result = [
- cos, -sin, 0,
- sin, cos, 0,
- 0, 0, 1
- ]
+ a00 = a[0, 0]
+ a01 = a[0, 1]
+ a02 = a[0, 2]
+ a03 = a[0, 3]
+ a10 = a[1, 0]
+ a11 = a[1, 1]
+ a12 = a[1, 2]
+ a13 = a[1, 3]
+ a20 = a[2, 0]
+ a21 = a[2, 1]
+ a22 = a[2, 2]
+ a23 = a[2, 3]
+ a30 = a[3, 0]
+ a31 = a[3, 1]
+ a32 = a[3, 2]
+ a33 = a[3, 3]
-proc rotate*(a: Mat3, angle: float32): Mat3 {.inline.} =
- # Rotates a matrix by an angle.
- a * rotationMat3(angle)
-
-proc `*`*(a: Mat3, b: Vec2): Vec2 =
- result.x = a[0, 0] * b.x + a[1, 0] * b.y + a[2, 0]
- result.y = a[0, 1] * b.x + a[1, 1] * b.y + a[2, 1]
-
-proc `*`*(a: Mat3, b: Vec3): Vec3 =
- result.x = a[0, 0] * b.x + a[1, 0] * b.y + a[2, 0] * b.z
- result.y = a[0, 1] * b.x + a[1, 1] * b.y + a[2, 1] * b.z
- result.z = a[0, 2] * b.x + a[1, 2] * b.y + a[2, 2] * b.z
-
-proc inverse*(a: Mat3): Mat3 =
let
- determinant = (
- a[0, 0] * (a[1, 1] * a[2, 2] - a[2, 1] * a[1, 2]) -
- a[0, 1] * (a[1, 0] * a[2, 2] - a[1, 2] * a[2, 0]) +
- a[0, 2] * (a[1, 0] * a[2, 1] - a[1, 1] * a[2, 0])
- )
- invDet = 1 / determinant
+ b00 = b[0, 0]
+ b01 = b[0, 1]
+ b02 = b[0, 2]
+ b03 = b[0, 3]
+ b10 = b[1, 0]
+ b11 = b[1, 1]
+ b12 = b[1, 2]
+ b13 = b[1, 3]
+ b20 = b[2, 0]
+ b21 = b[2, 1]
+ b22 = b[2, 2]
+ b23 = b[2, 3]
+ b30 = b[3, 0]
+ b31 = b[3, 1]
+ b32 = b[3, 2]
+ b33 = b[3, 3]
- result[0, 0] = (a[1, 1] * a[2, 2] - a[2, 1] * a[1, 2]) * invDet
- result[0, 1] = -(a[0, 1] * a[2, 2] - a[0, 2] * a[2, 1]) * invDet
- result[0, 2] = (a[0, 1] * a[1, 2] - a[0, 2] * a[1, 1]) * invDet
+ result[0, 0] = b00 * a00 + b01 * a10 + b02 * a20 + b03 * a30
+ result[0, 1] = b00 * a01 + b01 * a11 + b02 * a21 + b03 * a31
+ result[0, 2] = b00 * a02 + b01 * a12 + b02 * a22 + b03 * a32
+ result[0, 3] = b00 * a03 + b01 * a13 + b02 * a23 + b03 * a33
- result[1, 0] = -(a[1, 0] * a[2, 2] - a[1, 2] * a[2, 0]) * invDet
- result[1, 1] = (a[0, 0] * a[2, 2] - a[0, 2] * a[2, 0]) * invDet
- result[1, 2] = -(a[0, 0] * a[1, 2] - a[1, 0] * a[0, 2]) * invDet
+ result[1, 0] = b10 * a00 + b11 * a10 + b12 * a20 + b13 * a30
+ result[1, 1] = b10 * a01 + b11 * a11 + b12 * a21 + b13 * a31
+ result[1, 2] = b10 * a02 + b11 * a12 + b12 * a22 + b13 * a32
+ result[1, 3] = b10 * a03 + b11 * a13 + b12 * a23 + b13 * a33
- result[2, 0] = (a[1, 0] * a[2, 1] - a[2, 0] * a[1, 1]) * invDet
- result[2, 1] = -(a[0, 0] * a[2, 1] - a[2, 0] * a[0, 1]) * invDet
- result[2, 2] = (a[0, 0] * a[1, 1] - a[1, 0] * a[0, 1]) * invDet
+ result[2, 0] = b20 * a00 + b21 * a10 + b22 * a20 + b23 * a30
+ result[2, 1] = b20 * a01 + b21 * a11 + b22 * a21 + b23 * a31
+ result[2, 2] = b20 * a02 + b21 * a12 + b22 * a22 + b23 * a32
+ result[2, 3] = b20 * a03 + b21 * a13 + b22 * a23 + b23 * a33
-proc pos*(a: Mat3): Vec2 {.inline.} =
- result.x = a[2, 0]
- result.y = a[2, 1]
+ result[3, 0] = b30 * a00 + b31 * a10 + b32 * a20 + b33 * a30
+ result[3, 1] = b30 * a01 + b31 * a11 + b32 * a21 + b33 * a31
+ result[3, 2] = b30 * a02 + b31 * a12 + b32 * a22 + b33 * a32
+ result[3, 3] = b30 * a03 + b31 * a13 + b32 * a23 + b33 * a33
-proc `pos=`*(a: var Mat3, b: Vec2) {.inline.} =
- a[2, 0] = b.x
- a[2, 1] = b.y
-
-proc hash*(a: Mat3): Hash {.inline.} =
- hash((
- a[0],
- a[1],
- a[2],
- a[3],
- a[4],
- a[5],
- a[6],
- a[7],
- a[8]
- ))
-
-type Mat4* = array[16, float32] ## 4x4 Matrix - OpenGL row order
-
-proc `[]`*(a: Mat4, i, j: int): float32 = a[i * 4 + j]
-proc `[]=`*(a: var Mat4, i, j: int, v: float32) = a[i * 4 + j] = v
-
-proc mat4*(
- v0, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15: float32
-): Mat4 {.inline.} =
+proc `*`*[T](a: GMat4[T], b: GVec3[T]): GVec3[T] =
[
- v0, v1, v2, v3,
- v4, v5, v6, v7,
- v8, v9, v10, v11,
- v12, v13, v14, v15
+ a[0, 0] * b.x + a[1, 0] * b.y + a[2, 0] * b.z + a[3, 0],
+ a[0, 1] * b.x + a[1, 1] * b.y + a[2, 1] * b.z + a[3, 1],
+ a[0, 2] * b.x + a[1, 2] * b.y + a[2, 2] * b.z + a[3, 2]
]
-proc mat4*(a: Mat4): Mat4 {.inline.} =
- a
-
-proc identity*(): Mat4 {.inline.} =
+proc transpose*[T](a: GMat3[T]): GMat3[T] =
[
- 1.float32, 0, 0, 0,
- 0, 1, 0, 0,
- 0, 0, 1, 0,
- 0, 0, 0, 1
+ [a[0, 0], a[1, 0], a[2, 0]],
+ [a[0, 1], a[1, 1], a[2, 1]],
+ [a[0, 2], a[1, 2], a[2, 2]]
]
-proc mat4*(): Mat4 {.inline.} =
- identity()
-
-proc `~=`*(a: Mat4, b: Mat4): bool =
- for i in 0 .. 15:
- if not(a[i] ~= b[i]):
- return false
- true
-
-proc transpose*(a: Mat4): Mat4 {.inline.} =
+proc transpose*[T](a: GMat4[T]): GMat4[T] =
[
- a[0, 0], a[1, 0], a[2, 0], a[3, 0],
- a[0, 1], a[1, 1], a[2, 1], a[3, 1],
- a[0, 2], a[1, 2], a[2, 2], a[3, 2],
- a[0, 3], a[1, 3], a[2, 3], a[3, 3]
+ [a[0, 0], a[1, 0], a[2, 0], a[3, 0]],
+ [a[0, 1], a[1, 1], a[2, 1], a[3, 1]],
+ [a[0, 2], a[1, 2], a[2, 2], a[3, 2]],
+ [a[0, 3], a[1, 3], a[2, 3], a[3, 3]]
]
-proc determinant*(a: Mat4): float32 =
+proc determinant*[T](a: GMat4[T]): T =
let
- a00 = a[0]
- a01 = a[1]
- a02 = a[2]
- a03 = a[3]
- a10 = a[4]
- a11 = a[5]
- a12 = a[6]
- a13 = a[7]
- a20 = a[8]
- a21 = a[9]
- a22 = a[10]
- a23 = a[11]
- a30 = a[12]
- a31 = a[13]
- a32 = a[14]
- a33 = a[15]
-
+ a00 = a[0, 0]
+ a01 = a[0, 1]
+ a02 = a[0, 2]
+ a03 = a[0, 3]
+ a10 = a[1, 0]
+ a11 = a[1, 1]
+ a12 = a[1, 2]
+ a13 = a[1, 3]
+ a20 = a[2, 0]
+ a21 = a[2, 1]
+ a22 = a[2, 2]
+ a23 = a[2, 3]
+ a30 = a[3, 0]
+ a31 = a[3, 1]
+ a32 = a[3, 2]
+ a33 = a[3, 3]
(
a30*a21*a12*a03 - a20*a31*a12*a03 - a30*a11*a22*a03 + a10*a31*a22*a03 +
a20*a11*a32*a03 - a10*a21*a32*a03 - a30*a21*a02*a13 + a20*a31*a02*a13 +
@@ -758,24 +616,45 @@ proc determinant*(a: Mat4): float32 =
a20*a01*a12*a33 - a00*a21*a12*a33 - a10*a01*a22*a33 + a00*a11*a22*a33
)
-proc inverse*(a: Mat4): Mat4 =
+proc inverse*[T](a: GMat3[T]): GMat3[T] =
let
- a00 = a[0]
- a01 = a[1]
- a02 = a[2]
- a03 = a[3]
- a10 = a[4]
- a11 = a[5]
- a12 = a[6]
- a13 = a[7]
- a20 = a[8]
- a21 = a[9]
- a22 = a[10]
- a23 = a[11]
- a30 = a[12]
- a31 = a[13]
- a32 = a[14]
- a33 = a[15]
+ determinant = (
+ a[0, 0] * (a[1, 1] * a[2, 2] - a[2, 1] * a[1, 2]) -
+ a[0, 1] * (a[1, 0] * a[2, 2] - a[1, 2] * a[2, 0]) +
+ a[0, 2] * (a[1, 0] * a[2, 1] - a[1, 1] * a[2, 0])
+ )
+ invDet = 1 / determinant
+
+ result[0, 0] = +(a[1, 1] * a[2, 2] - a[2, 1] * a[1, 2]) * invDet
+ result[0, 1] = -(a[0, 1] * a[2, 2] - a[0, 2] * a[2, 1]) * invDet
+ result[0, 2] = +(a[0, 1] * a[1, 2] - a[0, 2] * a[1, 1]) * invDet
+
+ result[1, 0] = -(a[1, 0] * a[2, 2] - a[1, 2] * a[2, 0]) * invDet
+ result[1, 1] = +(a[0, 0] * a[2, 2] - a[0, 2] * a[2, 0]) * invDet
+ result[1, 2] = -(a[0, 0] * a[1, 2] - a[1, 0] * a[0, 2]) * invDet
+
+ result[2, 0] = +(a[1, 0] * a[2, 1] - a[2, 0] * a[1, 1]) * invDet
+ result[2, 1] = -(a[0, 0] * a[2, 1] - a[2, 0] * a[0, 1]) * invDet
+ result[2, 2] = +(a[0, 0] * a[1, 1] - a[1, 0] * a[0, 1]) * invDet
+
+proc inverse*[T](a: GMat4[T]): GMat4[T] =
+ let
+ a00 = a[0, 0]
+ a01 = a[0, 1]
+ a02 = a[0, 2]
+ a03 = a[0, 3]
+ a10 = a[1, 0]
+ a11 = a[1, 1]
+ a12 = a[1, 2]
+ a13 = a[1, 3]
+ a20 = a[2, 0]
+ a21 = a[2, 1]
+ a22 = a[2, 2]
+ a23 = a[2, 3]
+ a30 = a[3, 0]
+ a31 = a[3, 1]
+ a32 = a[3, 2]
+ a33 = a[3, 3]
let
b00 = a00 * a11 - a01 * a10
@@ -792,157 +671,69 @@ proc inverse*(a: Mat4): Mat4 =
b11 = a22 * a33 - a23 * a32
# Calculate the inverse determinant.
- let invDet = 1.0/(b00*b11 - b01*b10 + b02*b09 + b03*b08 - b04*b07 + b05*b06)
+ let invDet = T(1.0)/(b00*b11 - b01*b10 + b02*b09 + b03*b08 - b04*b07 + b05*b06)
- result[00] = (+a11 * b11 - a12 * b10 + a13 * b09) * invDet
- result[01] = (-a01 * b11 + a02 * b10 - a03 * b09) * invDet
- result[02] = (+a31 * b05 - a32 * b04 + a33 * b03) * invDet
- result[03] = (-a21 * b05 + a22 * b04 - a23 * b03) * invDet
- result[04] = (-a10 * b11 + a12 * b08 - a13 * b07) * invDet
- result[05] = (+a00 * b11 - a02 * b08 + a03 * b07) * invDet
- result[06] = (-a30 * b05 + a32 * b02 - a33 * b01) * invDet
- result[07] = (+a20 * b05 - a22 * b02 + a23 * b01) * invDet
- result[08] = (+a10 * b10 - a11 * b08 + a13 * b06) * invDet
- result[09] = (-a00 * b10 + a01 * b08 - a03 * b06) * invDet
- result[10] = (+a30 * b04 - a31 * b02 + a33 * b00) * invDet
- result[11] = (-a20 * b04 + a21 * b02 - a23 * b00) * invDet
- result[12] = (-a10 * b09 + a11 * b07 - a12 * b06) * invDet
- result[13] = (+a00 * b09 - a01 * b07 + a02 * b06) * invDet
- result[14] = (-a30 * b03 + a31 * b01 - a32 * b00) * invDet
- result[15] = (+a20 * b03 - a21 * b01 + a22 * b00) * invDet
+ result[0, 0] = (+a11 * b11 - a12 * b10 + a13 * b09) * invDet
+ result[0, 1] = (-a01 * b11 + a02 * b10 - a03 * b09) * invDet
+ result[0, 2] = (+a31 * b05 - a32 * b04 + a33 * b03) * invDet
+ result[0, 3] = (-a21 * b05 + a22 * b04 - a23 * b03) * invDet
-proc `*`*(a, b: Mat4): Mat4 =
+ result[1, 0] = (-a10 * b11 + a12 * b08 - a13 * b07) * invDet
+ result[1, 1] = (+a00 * b11 - a02 * b08 + a03 * b07) * invDet
+ result[1, 2] = (-a30 * b05 + a32 * b02 - a33 * b01) * invDet
+ result[1, 3] = (+a20 * b05 - a22 * b02 + a23 * b01) * invDet
+
+ result[2, 0] = (+a10 * b10 - a11 * b08 + a13 * b06) * invDet
+ result[2, 1] = (-a00 * b10 + a01 * b08 - a03 * b06) * invDet
+ result[2, 2] = (+a30 * b04 - a31 * b02 + a33 * b00) * invDet
+ result[2, 3] = (-a20 * b04 + a21 * b02 - a23 * b00) * invDet
+
+ result[3, 0] = (-a10 * b09 + a11 * b07 - a12 * b06) * invDet
+ result[3, 1] = (+a00 * b09 - a01 * b07 + a02 * b06) * invDet
+ result[3, 2] = (-a30 * b03 + a31 * b01 - a32 * b00) * invDet
+ result[3, 3] = (+a20 * b03 - a21 * b01 + a22 * b00) * invDet
+
+proc scale*[T](v: GVec2[T]): GMat3[T] =
+ [
+ [v.x, 0, 0],
+ [T(0), v.y, 0],
+ [T(0), 0, 1]
+ ]
+
+proc scale*[T](v: GVec3[T]): GMat4[T] =
+ [
+ [v.x, 0, 0, 0],
+ [T(0), v.y, 0, 0],
+ [T(0), 0, v.z, 0],
+ [T(0), 0, 0, 1]
+ ]
+
+proc translate*[T](v: GVec2[T]): GMat3[T] =
+ [
+ [T(1), 0, 0],
+ [T(0), 1, 0],
+ [v.x, v.y, 1]
+ ]
+
+proc translate*[T](v: GVec3[T]): GMat4[T] =
+ [
+ [T(1), 0, 0, 0],
+ [T(0), 1, 0, 0],
+ [T(0), 0, 1, 0],
+ [v.x, v.y, v.z, 1]
+ ]
+
+proc rotate*[T](angle: T): GMat3[T] =
let
- a00 = a[0]
- a01 = a[1]
- a02 = a[2]
- a03 = a[3]
- a10 = a[4]
- a11 = a[5]
- a12 = a[6]
- a13 = a[7]
- a20 = a[8]
- a21 = a[9]
- a22 = a[10]
- a23 = a[11]
- a30 = a[12]
- a31 = a[13]
- a32 = a[14]
- a33 = a[15]
+ sin = sin(angle)
+ cos = cos(angle)
+ [
+ [cos, -sin, 0],
+ [sin, cos, 0],
+ [T(0), 0, 1]
+ ]
- let
- b00 = b[0]
- b01 = b[1]
- b02 = b[2]
- b03 = b[3]
- b10 = b[4]
- b11 = b[5]
- b12 = b[6]
- b13 = b[7]
- b20 = b[8]
- b21 = b[9]
- b22 = b[10]
- b23 = b[11]
- b30 = b[12]
- b31 = b[13]
- b32 = b[14]
- b33 = b[15]
-
- result[00] = b00 * a00 + b01 * a10 + b02 * a20 + b03 * a30
- result[01] = b00 * a01 + b01 * a11 + b02 * a21 + b03 * a31
- result[02] = b00 * a02 + b01 * a12 + b02 * a22 + b03 * a32
- result[03] = b00 * a03 + b01 * a13 + b02 * a23 + b03 * a33
- result[04] = b10 * a00 + b11 * a10 + b12 * a20 + b13 * a30
- result[05] = b10 * a01 + b11 * a11 + b12 * a21 + b13 * a31
- result[06] = b10 * a02 + b11 * a12 + b12 * a22 + b13 * a32
- result[07] = b10 * a03 + b11 * a13 + b12 * a23 + b13 * a33
- result[08] = b20 * a00 + b21 * a10 + b22 * a20 + b23 * a30
- result[09] = b20 * a01 + b21 * a11 + b22 * a21 + b23 * a31
- result[10] = b20 * a02 + b21 * a12 + b22 * a22 + b23 * a32
- result[11] = b20 * a03 + b21 * a13 + b22 * a23 + b23 * a33
- result[12] = b30 * a00 + b31 * a10 + b32 * a20 + b33 * a30
- result[13] = b30 * a01 + b31 * a11 + b32 * a21 + b33 * a31
- result[14] = b30 * a02 + b31 * a12 + b32 * a22 + b33 * a32
- result[15] = b30 * a03 + b31 * a13 + b32 * a23 + b33 * a33
-
-proc `*`*(a: Mat4, b: Vec3): Vec3 =
- result.x = a[0] * b.x + a[4] * b.y + a[8] * b.z + a[12]
- result.y = a[1] * b.x + a[5] * b.y + a[9] * b.z + a[13]
- result.z = a[2] * b.x + a[6] * b.y + a[10] * b.z + a[14]
-
-proc `*`*(a: Mat4, b: Vec4): Vec4 =
- result.x = a[0] * b.x + a[4] * b.y + a[8] * b.z + a[12] * b.w
- result.y = a[1] * b.x + a[5] * b.y + a[9] * b.z + a[13] * b.w
- result.z = a[2] * b.x + a[6] * b.y + a[10] * b.z + a[14] * b.w
- result.w = a[3] * b.x + a[7] * b.y + a[11] * b.z + a[15] * b.w
-
-proc right*(a: Mat4): Vec3 {.inline.} =
- result.x = a[0]
- result.y = a[1]
- result.z = a[2]
-
-proc `right=`*(a: var Mat4, b: Vec3) {.inline.} =
- a[0] = b.x
- a[1] = b.y
- a[2] = b.z
-
-proc up*(a: Mat4): Vec3 {.inline.} =
- result.x = a[4]
- result.y = a[5]
- result.z = a[6]
-
-proc `up=`*(a: var Mat4, b: Vec3) {.inline.} =
- a[4] = b.x
- a[5] = b.y
- a[6] = b.z
-
-proc forward*(a: Mat4): Vec3 {.inline.} =
- result.x = a[8]
- result.y = a[9]
- result.z = a[10]
-
-proc `forward=`*(a: var Mat4, b: Vec3) {.inline.} =
- a[8] = b.x
- a[9] = b.y
- a[10] = b.z
-
-proc pos*(a: Mat4): Vec3 {.inline.} =
- result.x = a[12]
- result.y = a[13]
- result.z = a[14]
-
-proc `pos=`*(a: var Mat4, b: Vec3) {.inline.} =
- a[12] = b.x
- a[13] = b.y
- a[14] = b.z
-
-proc rotationOnly*(a: Mat4): Mat4 {.inline.} =
- result = a
- result.pos = vec3(0, 0, 0)
-
-proc dist*(a, b: Mat4): float32 {.inline.} =
- let
- x = a[12] - b[12]
- y = a[13] - b[13]
- z = a[14] - b[14]
- sqrt(x * x + y * y + z * z)
-
-proc translate*(v: Vec3): Mat4 =
- result[0] = 1
- result[5] = 1
- result[10] = 1
- result[15] = 1
- result[12] = v.x
- result[13] = v.y
- result[14] = v.z
-
-proc scale*(v: Vec3): Mat4 =
- result[0] = v.x
- result[5] = v.y
- result[10] = v.z
- result[15] = 1
-
-proc hrp*(m: Mat4): Vec3 =
+proc hrp*[T](m: GMat4[T]): GVec3[T] =
var heading, pitch, roll: float32
if m[1] > 0.998: # singularity at north pole
heading = arctan2(m[2], m[10])
@@ -956,61 +747,67 @@ proc hrp*(m: Mat4): Vec3 =
heading = arctan2(-m[8], m[0])
pitch = arctan2(-m[6], m[5])
roll = arcsin(m[4])
- result.x = heading
- result.y = pitch
- result.z = roll
+ [heading, pitch, roll]
-proc frustum*(left, right, bottom, top, near, far: float32): Mat4 =
+proc frustum*[T](left, right, bottom, top, near, far: T): GMat4[T] =
let
rl = (right - left)
tb = (top - bottom)
fn = (far - near)
- result[0] = (near * 2) / rl
- result[1] = 0
- result[2] = 0
- result[3] = 0
- result[4] = 0
- result[5] = (near * 2) / tb
- result[6] = 0
- result[7] = 0
- result[8] = (right + left) / rl
- result[9] = (top + bottom) / tb
- result[10] = -(far + near) / fn
- result[11] = -1
- result[12] = 0
- result[13] = 0
- result[14] = -(far * near * 2) / fn
- result[15] = 0
-proc perspective*(fovy, aspect, near, far: float32): Mat4 =
+ result[0, 0] = (near * 2) / rl
+ result[0, 1] = 0
+ result[0, 2] = 0
+ result[0, 3] = 0
+
+ result[1, 0] = 0
+ result[1, 1] = (near * 2) / tb
+ result[1, 2] = 0
+ result[1, 3] = 0
+
+ result[2, 0] = (right + left) / rl
+ result[2, 1] = (top + bottom) / tb
+ result[2, 2] = -(far + near) / fn
+ result[2, 3] = -1
+
+ result[3, 0] = 0
+ result[3, 1] = 0
+ result[3, 2] = -(far * near * 2) / fn
+ result[3, 3] = 0
+
+proc perspective*[T](fovy, aspect, near, far: T): GMat4[T] =
let
top = near * tan(fovy * PI / 360.0)
right = top * aspect
frustum(-right, right, -top, top, near, far)
-proc ortho*(left, right, bottom, top, near, far: float32): Mat4 =
+proc ortho*[T](left, right, bottom, top, near, far: T): GMat4[T] =
let
rl = (right - left)
tb = (top - bottom)
fn = (far - near)
- result[0] = 2 / rl
- result[1] = 0
- result[2] = 0
- result[3] = 0
- result[4] = 0
- result[5] = 2 / tb
- result[6] = 0
- result[7] = 0
- result[8] = 0
- result[9] = 0
- result[10] = -2 / fn
- result[11] = 0
- result[12] = -(left + right) / rl
- result[13] = -(top + bottom) / tb
- result[14] = -(far + near) / fn
- result[15] = 1
-proc lookAt*(eye, center, up: Vec3): Mat4 =
+ result[0, 0] = 2 / rl
+ result[0, 1] = 0
+ result[0, 2] = 0
+ result[0, 3] = 0
+
+ result[1, 0] = 0
+ result[1, 1] = 2 / tb
+ result[1, 2] = 0
+ result[1, 3] = 0
+
+ result[2, 0] = 0
+ result[2, 1] = 0
+ result[2, 2] = -2 / fn
+ result[2, 3] = 0
+
+ result[3, 0] = -(left + right) / rl
+ result[3, 1] = -(top + bottom) / tb
+ result[3, 2] = -(far + near) / fn
+ result[3, 3] = 1
+
+proc lookAt*[T](eye, center: GVec3[T], up = [T(0), 0, 1]): GMat4[T] =
let
eyex = eye[0]
eyey = eye[1]
@@ -1023,7 +820,7 @@ proc lookAt*(eye, center, up: Vec3): Mat4 =
centerz = center[2]
if eyex == centerx and eyey == centery and eyez == centerz:
- return identity()
+ return mat4[T]()
var
# vec3.direction(eye, center, z)
@@ -1070,424 +867,204 @@ proc lookAt*(eye, center, up: Vec3): Mat4 =
y1 *= len
y2 *= len
- result[0] = x0
- result[1] = y0
- result[2] = z0
- result[3] = 0
- result[4] = x1
- result[5] = y1
- result[6] = z1
- result[7] = 0
- result[8] = x2
- result[9] = y2
- result[10] = z2
- result[11] = 0
- result[12] = -(x0 * eyex + x1 * eyey + x2 * eyez)
- result[13] = -(y0 * eyex + y1 * eyey + y2 * eyez)
- result[14] = -(z0 * eyex + z1 * eyey + z2 * eyez)
- result[15] = 1
-
-proc mat3*(m: Mat4): Mat3 =
- ## Gets rotation and translation, ignoring z coordinates.
- result[0, 0] = m[0, 0]
- result[0, 1] = m[0, 1]
- result[0, 2] = 0
- result[1, 0] = m[1, 0]
- result[1, 1] = m[1, 1]
- result[1, 2] = 0
- result[2, 0] = m[3, 0]
- result[2, 1] = m[3, 1]
- result[2, 2] = 0
-
-proc mat3Rotation*(m: Mat4): Mat3 =
- ## Gets the rotational part of the 4x4 matrix.
- result[0, 0] = m[0, 0]
- result[0, 1] = m[0, 1]
- result[0, 2] = m[0, 2]
- result[1, 0] = m[1, 0]
- result[1, 1] = m[1, 1]
- result[1, 2] = m[1, 2]
- result[2, 0] = m[2, 0]
- result[2, 1] = m[2, 1]
- result[2, 2] = m[2, 2]
-
-proc mat4*(m: Mat3): Mat4 =
- ## Takes a 2d Mat3 with position and converts to a 3d matrix.
- result[0, 0] = m[0, 0]
- result[0, 1] = m[0, 1]
- result[0, 2] = 0
+ result[0, 0] = x0
+ result[0, 1] = y0
+ result[0, 2] = z0
result[0, 3] = 0
- result[1, 0] = m[1, 0]
- result[1, 1] = m[1, 1]
- result[1, 2] = 0
+ result[1, 0] = x1
+ result[1, 1] = y1
+ result[1, 2] = z1
result[1, 3] = 0
- result[2, 0] = 0
- result[2, 1] = 0
- result[2, 2] = 1
+ result[2, 0] = x2
+ result[2, 1] = y2
+ result[2, 2] = z2
result[2, 3] = 0
- result[3, 0] = m[2, 0]
- result[3, 1] = m[2, 1]
- result[3, 2] = 0
+ result[3, 0] = -(x0 * eyex + x1 * eyey + x2 * eyez)
+ result[3, 1] = -(y0 * eyex + y1 * eyey + y2 * eyez)
+ result[3, 2] = -(z0 * eyex + z1 * eyey + z2 * eyez)
result[3, 3] = 1
-proc mat4Rotation*(m: Mat3): Mat4 =
- ## Gets the rotational part of the 3x3 matrix into a 4x4 matrix.
- result[0, 0] = m[0, 0]
- result[0, 1] = m[0, 1]
- result[0, 2] = m[0, 2]
- result[1, 0] = m[1, 0]
- result[1, 1] = m[1, 1]
- result[1, 2] = m[1, 2]
- result[2, 0] = m[2, 0]
- result[2, 1] = m[2, 1]
- result[2, 2] = m[2, 2]
+proc angle*[T](a: GVec2[T]): T =
+ ## Angle of a Vec2.
+ arctan2(a.y, a.x)
-proc hash*(a: Mat4): Hash {.inline.} =
- hash((
- a[0],
- a[1],
- a[2],
- a[3],
- a[4],
- a[5],
- a[6],
- a[7],
- a[8],
- a[9],
- a[10],
- a[11],
- a[12],
- a[13],
- a[14],
- a[15],
- ))
+proc angle*[T](a, b: GVec2[T]): T =
+ ## Angle between 2 Vec2.
+ fixAngle(arctan2(a.y - b.y, a.x - b.x))
-proc `$`*(a: Mat4): string =
- &"""[{a[0]:.5f}, {a[1]:.5f}, {a[2]:.5f}, {a[3]:.5f},
-{a[4]:.5f}, {a[5]:.5f}, {a[6]:.5f}, {a[7]:.5f},
-{a[8]:.5f}, {a[9]:.5f}, {a[10]:.5f}, {a[11]:.5f},
-{a[12]:.5f}, {a[13]:.5f}, {a[14]:.5f}, {a[15]:.5f}]"""
+proc angle*[T](a, b: GVec3[T]): T =
+ ## Angle between 2 Vec3.
+ var dot = dot(a, b)
+ dot = dot / (a.length * b.length)
+ arccos(dot)
-type Quat* = object
- x*: float32
- y*: float32
- z*: float32
- w*: float32
+type
+ Quat* = GVec4[float32]
+ DQuat* = GVec4[float64]
-proc quat*(x, y, z, w: float32): Quat {.inline.} =
- result.x = x
- result.y = y
- result.z = z
- result.w = w
+template genQuatConstructor(lower, upper, typ: untyped) =
-proc `~=`*(a, b: Quat): bool =
- a.x ~= b.x and a.y ~= b.y and a.z ~= b.z and a.w ~= b.w
+ proc `lower`*(): `upper` = gvec4[typ](0, 0, 0, 1)
+ proc `lower`*(x, y, z, w: typ): `upper` = gvec4[typ](x, y, z, w)
+ proc `lower`*(x: typ): `upper` = gvec4[typ](x, x, x, x)
+ proc `lower`*[T](x: GVec4[T]): `upper` =
+ gvec4[typ](typ(x[0]), typ(x[1]), typ(x[2]), typ(x[3]))
-proc conjugate*(q: Quat): Quat {.inline.} =
- result.w = +q.w
- result.x = -q.x
- result.y = -q.y
- result.z = -q.z
+genQuatConstructor(quat, Quat, float32)
+genQuatConstructor(dquat, DQuat, float64)
-proc length*(q: Quat): float32 {.inline.} =
- sqrt(
- q.w * q.w +
- q.x * q.x +
- q.y * q.y +
- q.z * q.z
- )
-
-proc normalize*(q: Quat): Quat =
- var m = q.length
- result.x = q.x / m
- result.y = q.y / m
- result.z = q.z / m
- result.w = q.w / m
-
-proc xyz*(q: Quat): Vec3 {.inline.} =
- result.x = q.x
- result.y = q.y
- result.z = q.z
-
-proc `xyz=`*(q: var Quat, v: Vec3) {.inline.} =
- q.x = v.x
- q.y = v.y
- q.z = v.z
-
-proc `-`*(a: var Quat): Quat {.inline.} =
- result.x = -a.x
- result.y = -a.y
- result.z = -a.z
- result.w = -a.w
-
-proc `+`*(a: Quat, b: Quat): Quat {.inline.} =
- result.x = a.x + b.x
- result.y = a.y + b.y
- result.z = a.z + b.z
- result.w = a.w + b.w
-
-proc `*`*(a, b: Quat): Quat =
- ## Multiply the quaternion by a quaternion.
- #[
- var q = quat(0,0,0,0)
- q.w = dot(a.xyz, b.xyz)
- var va = cross(a.xyz, b.xyz)
- var vb = a.xyz * b.w
- var vc = b.xyz * a.w
- va = va + vb
- q.xyz = va + vc
- return q.normalize()
- ]#
-
- result.x = a.x * b.w + a.w * b.x + a.y * b.z - a.z * b.y
- result.y = a.y * b.w + a.w * b.y + a.z * b.x - a.x * b.z
- result.z = a.z * b.w + a.w * b.z + a.x * b.y - a.y * b.x
- result.w = a.w * b.w - a.x * b.x - a.y * b.y - a.z * b.z
-
-proc `*`*(q: Quat, v: float32): Quat {.inline.} =
- ## Multiply the quaternion by a float32.
- result.x = q.x * v
- result.y = q.y * v
- result.z = q.z * v
- result.w = q.w * v
-
-proc `/`*(q: Quat, v: float32): Quat {.inline.} =
- ## Divide the quaternion by a float32.
- result.x = q.x / v
- result.y = q.y / v
- result.z = q.z / v
- result.w = q.w / v
-
-proc `*=`*(a: var Quat, b: float32) {.inline.} =
- a = a * b
-
-proc `/=`*(a: var Quat, b: float32) {.inline.} =
- a = a / b
-
-proc `*`*(q: Quat, v: Vec3): Vec3 =
- ## Multiply the quaternion by a vector.
- let
- x = v.x
- y = v.y
- z = v.z
-
- qx = q.x
- qy = q.y
- qz = q.z
- qw = q.w
-
- ix = +qw * x + qy * z - qz * y
- iy = +qw * y + qz * x - qx * z
- iz = +qw * z + qx * y - qy * x
- iw = -qx * x - qy * y - qz * z
-
- result.x = ix * qw + iw * -qx + iy * -qz - iz * -qy
- result.y = iy * qw + iw * -qy + iz * -qx - ix * -qz
- result.z = iz * qw + iw * -qz + ix * -qy - iy * -qx
-
-proc `[]`*(a: var Quat, i: int, b: float32) =
- case i
- of 0: a.x
- of 1: a.y
- of 2: a.z
- of 3: a.w
- else: raise newException(IndexDefect, "Index not in 0 .. 3")
-
-proc `[]=`*(a: var Quat, i: int, b: float32) =
- case i
- of 0: a.x = b
- of 1: a.y = b
- of 2: a.z = b
- of 3: a.w = b
- else: raise newException(IndexDefect, "Index not in 0 .. 3")
-
-proc mat3*(q: Quat): Mat3 =
- let
- xx = q.x * q.x
- xy = q.x * q.y
- xz = q.x * q.z
- xw = q.x * q.w
-
- yy = q.y * q.y
- yz = q.y * q.z
- yw = q.y * q.w
-
- zz = q.z * q.z
- zw = q.z * q.w
-
- result[0] = 1 - 2 * (yy + zz)
- result[1] = 0 + 2 * (xy - zw)
- result[2] = 0 + 2 * (xz + yw)
- result[3] = 0 + 2 * (xy + zw)
- result[4] = 1 - 2 * (xx + zz)
- result[5] = 0 + 2 * (yz - xw)
- result[6] = 0 + 2 * (xz - yw)
- result[7] = 0 + 2 * (yz + xw)
- result[8] = 1 - 2 * (xx + yy)
-
-proc mat4*(q: Quat): Mat4 =
- let
- xx = q.x * q.x
- xy = q.x * q.y
- xz = q.x * q.z
- xw = q.x * q.w
-
- yy = q.y * q.y
- yz = q.y * q.z
- yw = q.y * q.w
-
- zz = q.z * q.z
- zw = q.z * q.w
-
- result[00] = 1 - 2 * (yy + zz)
- result[01] = 0 + 2 * (xy - zw)
- result[02] = 0 + 2 * (xz + yw)
- result[04] = 0 + 2 * (xy + zw)
- result[05] = 1 - 2 * (xx + zz)
- result[06] = 0 + 2 * (yz - xw)
- result[08] = 0 + 2 * (xz - yw)
- result[09] = 0 + 2 * (yz + xw)
- result[10] = 1 - 2 * (xx + yy)
-
- result[3] = 0
- result[7] = 0
- result[11] = 0
- result[12] = 0
- result[13] = 0
- result[14] = 0
- result[15] = 1.0
-
-proc reciprocalSqrt*(x: float32): float32 {.inline.} =
- 1.0 / sqrt(x)
-
-proc quat*(m: Mat4): Quat =
- let
- m00 = m[0]
- m01 = m[4]
- m02 = m[8]
-
- m10 = m[1]
- m11 = m[5]
- m12 = m[9]
-
- m20 = m[2]
- m21 = m[6]
- m22 = m[10]
-
- var
- q: Quat
- t: float32
-
- if m22 < 0:
- if m00 > m11:
- t = 1 + m00 - m11 - m22
- q = quat(t, m01 + m10, m20 + m02, m12 - m21)
- else:
- t = 1 - m00 + m11 - m22
- q = quat(m01 + m10, t, m12 + m21, m20 - m02)
- else:
- if m00 < - m11:
- t = 1 - m00 - m11 + m22
- q = quat(m20 + m02, m12 + m21, t, m01 - m10)
- else:
- t = 1 + m00 + m11 + m22
- q = quat(m12 - m21, m20 - m02, m01 - m10, t)
- q = q * (0.5 / sqrt(t))
-
- assert abs(q.length - 1.0) < 0.001
- q
-
-proc fromAxisAngle*(axis: Vec3, angle: float32): Quat =
+proc fromAxisAngle*[T](axis: GVec3[T], angle: T): GVec4[T] =
let
a = axis.normalize()
s = sin(angle / 2)
- result.x = a.x * s
- result.y = a.y * s
- result.z = a.z * s
- result.w = cos(angle / 2)
+ [
+ a.x * s,
+ a.y * s,
+ a.z * s,
+ cos(angle / 2)
+ ]
-proc toAxisAngle*(q: Quat, axis: var Vec3, angle: var float32) =
- var cosAngle = q.w
- angle = arccos(cosAngle) * 2.0
- var sinAngle = sqrt(1.0 - cosAngle * cosAngle)
+proc toAxisAngle*[T](q: GVec4[T]): (GVec3[T], T) =
+ let cosAngle = q.w
+ let angle = arccos(cosAngle) * 2.0
+ var
+ sinAngle = sqrt(1.0 - cosAngle * cosAngle)
+ axis: GVec4[T]
if abs(sinAngle) < 0.0005:
sinAngle = 1.0
- axis.x = q.x / sinAngle
- axis.y = q.y / sinAngle
- axis.z = q.z / sinAngle
+ axis.x = [
+ q.x / sinAngle,
+ q.y / sinAngle,
+ q.z / sinAngle
+ ]
+ return (axis, angle)
-proc quat*(heading, pitch, roll: float32): Quat =
+proc orthogonal*[T](v: GVec3[T]): GVec3[T] =
+ let v = abs(v)
+ var other: type(v) =
+ if v.x < v.y:
+ if v.x < v.z:
+ [T(1), 0, 0] # X_AXIS
+ else:
+ [T(0), 0, 1] # Z_AXIS
+ elif v.y < v.z:
+ [T(0), 1, 0] # Y_AXIS
+ else:
+ [T(0), 0, 1] # Z_AXIS
+ return cross(v, other)
+
+proc fromTwoVectors*[T](a, b: GVec3[T]): GVec4[T] =
+ ## Return a quat that would take a and rotate it into b.
+
+ # It is important that the inputs are of equal length when
+ # calculating the half-way vector.
let
- t0 = cos(heading * 0.5)
- t1 = sin(heading * 0.5)
- t2 = cos(roll * 0.5)
- t3 = sin(roll * 0.5)
- t4 = cos(pitch * 0.5)
- t5 = sin(pitch * 0.5)
- result.w = t0 * t2 * t4 + t1 * t3 * t5
- result.x = t0 * t3 * t4 - t1 * t2 * t5
- result.y = t0 * t2 * t5 + t1 * t3 * t4
- result.z = t1 * t2 * t4 - t0 * t3 * t5
+ u = b.normalize()
+ v = a.normalize()
-proc quat*(hpr: Vec3): Quat {.inline.} =
- quat(hpr.x, hpr.y, hpr.z)
+ # Unfortunately, we have to check for when u == -v, as u + v
+ # in this case will be (0, 0, 0), which cannot be normalized.
+ if (u == -v):
+ # 180 degree rotation around any orthogonal vector
+ let q = normalize(orthogonal(u))
+ return [q.x, q.y, q.z, 0]
-proc hrp*(q: Quat): Vec3 =
- var ysqr = q.y * q.y
- # roll
- var t0 = +2.0 * (q.w * q.x + q.y * q.z)
- var t1 = +1.0 - 2.0 * (q.x * q.x + ysqr)
- result.z = arctan2(t0, t1)
- # pitch
- var t2 = +2.0 * (q.w * q.y - q.z * q.x)
- if t2 > 1.0:
- t2 = 1.0
- if t2 < -1.0:
- t2 = -1.0
- result.y = arcsin(t2)
- # heading
- var t3 = +2.0 * (q.w * q.z + q.x * q.y)
- var t4 = +1.0 - 2.0 * (ysqr + q.z * q.z)
- result.x = arctan2(t3, t4)
+ let
+ half = normalize(u + v)
+ q = cross(u, half)
+ w = dot(u, half)
+ return [q.x, q.y, q.z, w]
-proc dot*(a: Quat, b: Quat): float32 {.inline.} =
- a.x * b.x + a.y * b.y + a.z * b.z + a.w * b.w
+proc quat*[T](m: GMat4[T]): GVec4[T] =
+ let
+ m00 = m[0, 0]
+ m01 = m[1, 0]
+ m02 = m[2, 0]
-proc nlerp*(a: Quat, b: Quat, v: float32): Quat =
- if dot(a, b) < 0:
- var c = a
- (-c * (1.0 - v) + b * v).normalize()
+ m10 = m[0, 1]
+ m11 = m[1, 1]
+ m12 = m[2, 1]
+
+ m20 = m[0, 2]
+ m21 = m[1, 2]
+ m22 = m[2, 2]
+
+ var
+ q: GVec4[T]
+ t: T
+
+ if m22 < 0:
+ if m00 > m11:
+ t = 1 + m00 - m11 - m22
+ q = gvec4(t, m01 + m10, m20 + m02, m12 - m21)
+ else:
+ t = 1 - m00 + m11 - m22
+ q = gvec4(m01 + m10, t, m12 + m21, m20 - m02)
else:
- (a * (1.0 - v) + b * v).normalize()
+ if m00 < - m11:
+ t = 1 - m00 - m11 + m22
+ q = gvec4(m20 + m02, m12 + m21, t, m01 - m10)
+ else:
+ t = 1 + m00 + m11 + m22
+ q = gvec4(m12 - m21, m20 - m02, m01 - m10, t)
+ q = q * (0.5 / sqrt(t))
-proc hash*(a: Quat): Hash {.inline.} =
- hash((a.x, a.y, a.z, a.w))
+ if abs(q.length - 1.0) > 0.001:
+ return [T(0), 0, 0, 1]
-proc `$`*(a: Quat): string =
- &"q({a.x:.8f}, {a.y:.8f}, {a.z:.8f}, {a.w:.8f})"
+ return q
-proc rotate*(angle: float32, axis: Vec3): Mat4 {.inline.} =
+proc mat4*[T](q: GVec4[T]): GMat4[T] =
+ let
+ xx = q.x * q.x
+ xy = q.x * q.y
+ xz = q.x * q.z
+ xw = q.x * q.w
+
+ yy = q.y * q.y
+ yz = q.y * q.z
+ yw = q.y * q.w
+
+ zz = q.z * q.z
+ zw = q.z * q.w
+
+ result[0, 0] = 1 - 2 * (yy + zz)
+ result[0, 1] = 0 + 2 * (xy - zw)
+ result[0, 2] = 0 + 2 * (xz + yw)
+ result[0, 3] = 0
+
+ result[1, 0] = 0 + 2 * (xy + zw)
+ result[1, 1] = 1 - 2 * (xx + zz)
+ result[1, 2] = 0 + 2 * (yz - xw)
+ result[1, 3] = 0
+
+ result[2, 0] = 0 + 2 * (xz - yw)
+ result[2, 1] = 0 + 2 * (yz + xw)
+ result[2, 2] = 1 - 2 * (xx + yy)
+ result[2, 3] = 0
+
+ result[3, 0] = 0
+ result[3, 1] = 0
+ result[3, 2] = 0
+ result[3, 3] = 1.0
+
+proc rotate*[T](angle: T, axis: GVec3[T]): GMat4[T] =
fromAxisAngle(axis, angle).mat4()
-proc rotateX*(angle: float32): Mat4 {.inline.} =
- rotate(angle, vec3(1, 0, 0))
+proc rotateX*[T](angle: T): GMat4[T] =
+ fromAxisAngle([T(1), 0, 0], angle).mat4()
-proc rotateY*(angle: float32): Mat4 {.inline.} =
- rotate(angle, vec3(0, 1, 0))
+proc rotateY*[T](angle: T): GMat4[T] =
+ fromAxisAngle([T(0), 1, 0], angle).mat4()
-proc rotateZ*(angle: float32): Mat4 {.inline.} =
- rotate(angle, vec3(0, 0, 1))
+proc rotateZ*[T](angle: T): GMat4[T] =
+ fromAxisAngle([T(0), 0, 1], angle).mat4()
-proc scaleMat*(scale: Vec3): Mat4 {.inline.} =
- result[0] = scale.x
- result[5] = scale.y
- result[10] = scale.z
- result[15] = 1.0
-
-proc scaleMat*(scale: float32): Mat4 {.inline.} =
- scaleMat(vec3(scale, scale, scale))
+when defined(release):
+ {.pop.}
+{.pop.}
diff --git a/tests/bench.nim b/tests/bench.nim
new file mode 100644
index 0000000..f9d3e51
--- /dev/null
+++ b/tests/bench.nim
@@ -0,0 +1,50 @@
+import benchy, vmath
+
+# TODO: I don't trust these simple benchmarks, make a better test.
+# echo "new vmath"
+# var v = vec3(1, 2, 3)
+# timeIt "+":
+# for i in 0 ..< 1_000_000:
+# v += vec3(4, 5, 6)
+
+# timeIt "-":
+# for i in 0 ..< 1_000_000:
+# v -= vec3(4, 5, 6)
+
+# timeIt "*":
+# for i in 0 ..< 1_000_000:
+# v *= PI
+
+# timeIt "/":
+# for i in 0 ..< 1_000_000:
+# v /= PI
+
+# timeIt "int +":
+# var v = ivec3(1, 2, 3)
+# for i in 0 ..< 1_000_000:
+# keep v + ivec3(4, 5, 6)
+
+# timeIt "int -":
+# var v = ivec3(1, 2, 3)
+# for i in 0 ..< 1_000_000:
+# keep v - ivec3(4, 5, 6)
+
+timeIt "matrix mat4":
+ var m = mat4()
+ for i in 0 ..< 10_000:
+ m = m *
+ rotate(0.2.float32, vec3(1, 0, 0)) *
+ scale(vec3(0.3)) *
+ translate(vec3(1))
+ keep m
+
+timeIt "matrix mat3":
+ var m = mat3()
+ for i in 0 ..< 10_000:
+ m = m * rotate(0.2.float32) * scale(vec2(0.3)) * translate(vec2(1))
+ keep m
+
+timeIt "matrix quat":
+ var m = rotate(0.2.float32, vec3(1, 0, 0)) * scale(vec3(0.3)) * translate(vec3(1))
+ for i in 0 ..< 100_000:
+ keep m.quat().mat4()
diff --git a/tests/test.nim b/tests/test.nim
index 9dc2465..b3c3aef 100644
--- a/tests/test.nim
+++ b/tests/test.nim
@@ -1,4 +1,4 @@
-import vmath, random
+import random, vmath
randomize(1234)
@@ -12,22 +12,30 @@ block:
doAssert not(0.001 ~= 0.002)
doAssert not(0.0001 ~= 0.0002)
doAssert not(0.00001 ~= 0.00002)
+
# Diff < epsilon.
doAssert 0.000001 ~= 0.000002
+ doAssert -0.000001 ~= -0.000002
doAssert vec2(1.0, 2.0) ~= vec2(1.0, 2.0)
doAssert vec3(1.0, 2.0, 3.0) ~= vec3(1.0, 2.0, 3.0)
doAssert vec4(1.0, 2.0, 3.0, 4.0) ~= vec4(1.0, 2.0, 3.0, 4.0)
doAssert quat(1.0, 2.0, 3.0, 4.0) ~= quat(1.0, 2.0, 3.0, 4.0)
+ doAssert dvec2(1) ~= dvec2(1)
+ doAssert dvec4(1, 2, 3, 4).xy ~= dvec2(1, 2)
+
+ when compiles(1 ~= 1):
+ doAssert false
+
block:
# Test simple functions.
doAssert between(0.5, 0, 1)
doAssert not between(1.5, 0, 1)
- doAssert sign(-1) == -1.0
- doAssert sign(0) == 1.0
- doAssert sign(1) == 1.0
+ doAssert sign(-1.0) == -1.0
+ doAssert sign(0.0) == 1.0
+ doAssert sign(1.0) == 1.0
doAssert quantize(1.23456789, 1.0) ~= 1
doAssert quantize(1.23456789, 0.1) ~= 1.2
@@ -51,9 +59,9 @@ block:
doAssert fixAngle(-3.1) ~= -3.1
doAssert fixAngle(-4.1) ~= 2.183185577392578
- doAssert angleBetween(0, 1.0) ~= 1.0
- doAssert angleBetween(0, PI) ~= PI
- doAssert angleBetween(0, PI + 0.2) ~= (-PI + 0.2)
+ doAssert angleBetween(0.0, 1.0) ~= 1.0
+ doAssert angleBetween(0.0, PI) ~= PI
+ doAssert angleBetween(0.0, PI + 0.2) ~= (-PI + 0.2)
doAssert angleBetween(0.1, 0.2) ~= 0.1
doAssert angleBetween(0.1, 0.2 + PI*2) ~= 0.1
doAssert angleBetween(0.1, 0.2 - PI*2) ~= 0.1
@@ -65,7 +73,7 @@ block:
doAssert angleBetween(0.2 + PI*2, 0.1) ~= -0.1
doAssert angleBetween(0.2 - PI*2, 0.1) ~= -0.1
- doAssert turnAngle(0, PI, 0.5) ~= 0.5
+ doAssert turnAngle(0.0, PI, 0.5) ~= 0.5
doAssert turnAngle(0.5, PI, 3.5) ~= PI
block:
@@ -133,6 +141,214 @@ block:
a /= n
doAssert a ~= vec4(1.0, 2.0, 3.0, 4.0)
+block:
+ # Test all type constructors compile
+ let
+ _ = bvec2(true, false)
+ _ = bvec3(true, false, true)
+ _ = bvec4(true, false, true, false)
+
+ _ = ivec2(-1, 2)
+ _ = ivec3(-1, 2, 3)
+ _ = ivec4(-1, 2, 3, 4)
+
+ _ = uvec2(1, 2)
+ _ = uvec3(1, 2, 3)
+ _ = uvec4(1, 2, 3, 4)
+
+ _ = vec2(1.0, 2.0)
+ _ = vec3(1.0, 2.0, 3.0)
+ _ = vec4(1.0, 2.0, 3.0, 4.0)
+
+ _ = dvec2(1.0, 2.0)
+ _ = dvec3(1.0, 2.0, 3.0)
+ _ = dvec4(1.0, 2.0, 3.0, 4.0)
+
+ _ = bvec2(true, false)
+ _ = bvec3(true, false, true)
+ _ = bvec4(true, false, true, false)
+
+ _ = ivec2(-1)
+ _ = ivec3(-1)
+ _ = ivec4(-1)
+
+ _ = uvec2(1)
+ _ = uvec3(1)
+ _ = uvec4(1)
+
+ _ = vec2(1.0)
+ _ = vec3(1.0)
+ _ = vec4(1.0)
+
+ _ = dvec2(1.0)
+ _ = dvec3(1.0)
+ _ = dvec4(1.0)
+
+block:
+ # Test basic vector mat constructors.
+ block:
+ let
+ _ = mat2()
+ _ = mat3()
+ _ = mat4()
+
+ block:
+ let
+ _ = mat2(
+ 1, 0,
+ 0, 1
+ )
+ _ = mat3(
+ 1, 0, 0,
+ 0, 1, 0,
+ 0, 0, 1
+ )
+ _ = mat4(
+ 1, 0, 0, 0,
+ 0, 1, 0, 0,
+ 0, 0, 1, 0,
+ 0, 0, 0, 1
+ )
+
+ block:
+ let
+ _ = mat2(
+ vec2(1, 0),
+ vec2(0, 1)
+ )
+ _ = mat3(
+ vec3(1, 0, 0),
+ vec3(0, 1, 0),
+ vec3(0, 0, 1)
+ )
+ _ = mat4(
+ vec4(1, 0, 0, 0),
+ vec4(0, 1, 0, 0),
+ vec4(0, 0, 1, 0),
+ vec4(0, 0, 0, 1)
+ )
+
+ block:
+ let
+ _ = dmat2()
+ _ = dmat3()
+ _ = dmat4()
+
+ block:
+ let
+ _ = dmat2(
+ 1, 0,
+ 0, 1
+ )
+ _ = dmat3(
+ 1, 0, 0,
+ 0, 1, 0,
+ 0, 0, 1
+ )
+ _ = dmat4(
+ 1, 0, 0, 0,
+ 0, 1, 0, 0,
+ 0, 0, 1, 0,
+ 0, 0, 0, 1
+ )
+
+ block:
+ let
+ _ = dmat2(
+ dvec2(1, 0),
+ dvec2(0, 1)
+ )
+ _ = dmat3(
+ dvec3(1, 0, 0),
+ dvec3(0, 1, 0),
+ dvec3(0, 0, 1)
+ )
+ _ = dmat4(
+ dvec4(1, 0, 0, 0),
+ dvec4(0, 1, 0, 0),
+ dvec4(0, 0, 1, 0),
+ dvec4(0, 0, 0, 1)
+ )
+
+block:
+ # Test basic mat functions.
+ doAssert dmat3().transpose() ~= [
+ [1.0, 0.0, 0.0],
+ [0.0, 1.0, 0.0],
+ [0.0, 0.0, 1.0]
+ ]
+ doAssert dmat4().transpose() ~= [
+ [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]
+ ]
+
+ doAssert scale(dvec2(1, 2)) ~= [
+ [1.0, 0.0, 0.0],
+ [0.0, 2.0, 0.0],
+ [0.0, 0.0, 1.0]
+ ]
+ doAssert scale(dvec3(2, 2, 3)) ~= [
+ [2.0, 0.0, 0.0, 0.0],
+ [0.0, 2.0, 0.0, 0.0],
+ [0.0, 0.0, 3.0, 0.0],
+ [0.0, 0.0, 0.0, 1.0]
+ ]
+
+ doAssert translate(dvec2(1, 2)) ~= [
+ [1.0, 0.0, 0.0],
+ [0.0, 1.0, 0.0],
+ [1.0, 2.0, 1.0]
+ ]
+ doAssert translate(dvec3(1, 2, 3)) ~= [
+ [1.0, 0.0, 0.0, 0.0],
+ [0.0, 1.0, 0.0, 0.0],
+ [0.0, 0.0, 1.0, 0.0],
+ [1.0, 2.0, 3.0, 1.0]
+ ]
+
+ doAssert rotate(1.0) ~= [
+ [0.5403023058681398, -0.8414709848078965, 0.0],
+ [0.8414709848078965, 0.5403023058681398, 0.0],
+ [0.0, 0.0, 1.0]
+ ]
+
+ doAssert scale(dvec2(2)) ~= [
+ [2.0, 0.0, 0.0],
+ [0.0, 2.0, 0.0],
+ [0.0, 0.0, 1.0]
+ ]
+ doAssert scale(dvec3(2)) ~= [
+ [2.0, 0.0, 0.0, 0.0],
+ [0.0, 2.0, 0.0, 0.0],
+ [0.0, 0.0, 2.0, 0.0],
+ [0.0, 0.0, 0.0, 1.0]
+ ]
+ doAssert translate(dvec2(2)) ~= [
+ [1.0, 0.0, 0.0],
+ [0.0, 1.0, 0.0],
+ [2.0, 2.0, 1.0]
+ ]
+ doAssert translate(dvec3(2)) ~= [
+ [1.0, 0.0, 0.0, 0.0],
+ [0.0, 1.0, 0.0, 0.0],
+ [0.0, 0.0, 1.0, 0.0],
+ [2.0, 2.0, 2.0, 1.0]
+ ]
+
+ doAssert rotate(1.0).inverse() ~= [
+ [0.5403023058681398, 0.8414709848078965, -0.0],
+ [-0.8414709848078965, 0.5403023058681398, -0.0],
+ [0.0, -0.0, 1.0]
+ ]
+ doAssert rotate(1.0, dvec3(1, 0, 0)).inverse() ~= [
+ [1.0, 0.0, 0.0, 0.0],
+ [-0.0, 0.5403022766113281, 0.8414710164070129, 0.0],
+ [0.0, -0.8414710164070129, 0.5403022766113281, 0.0],
+ [0.0, 0.0, 0.0, 1.0]
+ ]
+
block:
# Test basic vector mat4 and quat.
var m1 = mat4(
@@ -163,59 +379,59 @@ block:
block:
# Test Y 90.
- var m1 = rotate(PI/2, vec3(0, 1, 0))
+ var m1 = rotate(PI/2, dvec3(0, 1, 0))
var q1 = m1.quat()
var m2 = q1.mat4()
doAssert m1 ~= m2
block:
# Test -Y 90.
- var m1 = rotate(PI/2, vec3(0, -1, 0))
+ var m1 = rotate(PI/2, dvec3(0, -1, 0))
var q1 = m1.quat()
var m2 = q1.mat4()
doAssert m1 ~= m2
block:
# Test X 90.
- var m1 = rotate(PI/2, vec3(1, 0, 0))
+ var m1 = rotate(PI/2, dvec3(1, 0, 0))
var q1 = m1.quat()
var m2 = q1.mat4()
doAssert m1 ~= m2
block:
# Test Y 90.
- var m1 = rotate(PI/2, vec3(1, 0, 0))
+ var m1 = rotate(PI/2, dvec3(1, 0, 0))
var q1 = m1.quat()
var m2 = q1.mat4()
doAssert m1 ~= m2
block:
# Test 1,1,1 1.11rad.
- var m1 = rotate(PI*1.11, vec3(1, 1, 1).normalize())
+ var m1 = rotate(PI*1.11, dvec3(1, 1, 1).normalize())
var q1 = m1.quat()
var m2 = q1.mat4()
doAssert m1 ~= m2
block:
# Test 1,1,1 1.11rad.
- var m1 = rotate(PI*1.11, vec3(-1, 1, 1).normalize())
+ var m1 = rotate(PI*1.11, dvec3(-1, 1, 1).normalize())
var q1 = m1.quat()
var m2 = q1.mat4()
doAssert m1 ~= m2
block:
# Test 1,1,1 1.11rad.
- var m1 = rotate(PI*1.11, vec3(-1, 0.34, 1.123).normalize())
+ var m1 = rotate(PI*1.11, dvec3(-1, 0.34, 1.123).normalize())
var q1 = m1.quat()
var m2 = q1.mat4()
doAssert m1 ~= m2
block:
# Test super random quat test.
- for i in 0 .. 100:
+ for i in 0 ..< 1000:
var m1 = rotate(
PI*rand(2.0),
- vec3(rand(2.0)-0.5, rand(2.0)-0.5, rand(2.0)-0.5).normalize()
+ dvec3(rand(2.0)-0.5, rand(2.0)-0.5, rand(2.0)-0.5).normalize()
)
var q1 = m1.quat()
var m2 = q1.mat4()
@@ -256,49 +472,62 @@ block:
77.64571380615234, 0.0, 1.0
)
- doAssert (a3.mat4 * b3.mat4).mat3 ~= mat3(
- 1.0000, 0.0000, 0.0000,
- 0.0000, 1.0000, 0.0000,
- 50.0000, 50.0000, 0.0000
- )
doAssert a3 * b3 ~= mat3(
1.0000, 0.0000, 0.0000,
0.0000, 1.0000, 0.0000,
50.0000, 50.0000, 1.0000
)
- doAssert (
- mat3(1,2,3,4,5,6,7,8,9).mat4Rotation *
- mat3(10,20,30,40,50,60,70,80,90).mat4Rotation
- ).mat3Rotation ~= mat3(
+ doAssert mat3(1, 2, 3, 4, 5, 6, 7, 8, 9) *
+ mat3(10, 20, 30, 40, 50, 60, 70, 80, 90) ~= mat3(
300.0000, 360.0000, 420.0000,
660.0000, 810.0000, 960.0000,
1020.0000, 1260.0000, 1500.0000
)
- doAssert mat3(1,2,3,4,5,6,7,8,9) * mat3(10,20,30,40,50,60,70,80,90) ~= mat3(
- 300.0000, 360.0000, 420.0000,
- 660.0000, 810.0000, 960.0000,
- 1020.0000, 1260.0000, 1500.0000
- )
- doAssert a3.mat4 * vec3(77.64571380615234, 0, 1) ~= vec3(50.0, 50.0, 1.0)
doAssert a3 * vec2(77.64571380615234, 0) ~= vec2(50.0, 50.0)
- doAssert a3 * vec3(77.64571380615234, 0, 1.0) ~= vec3(50.0, 50.0, 1.0)
block:
- # hashing
- doAssert hash(vec2(PI, E)) == 1311648097060332001
- doAssert hash(vec3(PI, E, TAU)) == 5625953707464987239
- doAssert hash(vec4(PI, E, TAU, sqrt(2.0))) == -6538384897102876123
- doAssert hash(quat(1, 0, 0, sqrt(2.0))) == 1497919211694084820
- doAssert hash( mat3(
- 300.0000, 360.0000, 420.0000,
- 660.0000, 810.0000, 960.0000,
- 1020.0000, 1260.0000, 1500.0000
- )) == -4194936143766837151
- doAssert hash(mat4(
- 1.00000, 0.00000, 0.00000, 0.00000,
- 0.00000, 1.00000, 0.00000, 0.00000,
- 0.00000, 0.00000, 1.00000, 0.00000,
- 7.00000, 8.00000, 9.00000, 1.00000
- )) == 7507518476139335223
+ # test quat and matrix lookat
+ doAssert lookAt(vec3(1, 2, 3), vec3(0, 0, 0)).quat ~=
+ quat(
+ 0.07232953608036041,
+ 0.3063928484916687,
+ 0.9237624406814575,
+ 0.2180707305669785
+ )
+ doAssert lookAt(vec3(0, 0, 0), vec3(0, 0, 0)).quat ~= quat(0.0, 0.0, 0.0, 1.0)
+ doAssert lookAt(vec3(1, 0, 0), vec3(0, 0, 0)).quat ~= quat(0.5, 0.5, 0.5, 0.5)
+ doAssert lookAt(vec3(0, 1, 0), vec3(0, 0, 0)).quat ~=
+ quat(
+ 0.0,
+ 0.7071067690849304,
+ 0.7071067690849304,
+ 0.0
+ )
+ doAssert lookAt(vec3(0, 0, 1), vec3(0, 0, 0)).quat ~= quat(0.0, 0.0, 0.0, 1.0)
+
+ # Test super random quat test.
+ for i in 0 ..< 1000:
+ var m1 = rotate(
+ PI*rand(2.0),
+ dvec3(rand(2.0)-0.5, rand(2.0)-0.5, rand(2.0)-0.5).normalize()
+ )
+ var q1 = m1.quat()
+ var m2 = q1.mat4()
+ doAssert m1 ~= m2
+
+block:
+ # test fromTwoVectors
+ let
+ a = vec3(1, 0, 0)
+ b = vec3(0, 1, 0)
+ q1 = fromTwoVectors(a, b)
+ doAssert q1.mat4 * a ~= b
+
+ for i in 0 ..< 1000:
+ let
+ a = vec3(rand(2.0)-0.5, rand(2.0)-0.5, rand(2.0)-0.5).normalize()
+ b = vec3(rand(2.0)-0.5, rand(2.0)-0.5, rand(2.0)-0.5).normalize()
+ q = fromTwoVectors(a, b)
+ doAssert q.mat4 * a ~= b
diff --git a/vmath.nimble b/vmath.nimble
index 26d8f4c..a90da73 100644
--- a/vmath.nimble
+++ b/vmath.nimble
@@ -1,6 +1,6 @@
-version = "0.5.0"
+version = "1.0.0"
author = "treeform"
-description = "Math vector library for graphical things."
+description = "Your single stop for vector math routines for 2d and 3d graphics."
license = "MIT"
srcDir = "src"