From 268876910394278f26bb133e7d95f616a485463a Mon Sep 17 00:00:00 2001 From: treeform Date: Sat, 4 Mar 2023 12:57:17 -0800 Subject: [PATCH 01/11] Right-hand z-forward coordinate system --- README.md | 38 ++++++++++ src/vmath.nim | 199 +++++++++++++++++++++++++++++++++++++++++-------- tests/test.nim | 156 ++++++++++++++++++++++++++++++++------ 3 files changed, 338 insertions(+), 55 deletions(-) diff --git a/README.md b/README.md index 14b9a07..fc55880 100644 --- a/README.md +++ b/README.md @@ -89,6 +89,44 @@ vmathObjArrayBased ................ 73.968 ms 74.292 ms ±0.631 x100 * [3d Ray Trace Benchmark](tests/bench_raytracer.nim) * [2d SVG Render Benchmark](https://github.com/treeform/pixie/blob/master/tests/bench_svg.nim) +## Zmod - GLSL mod + +GLSL uses a different type of float point mod. Because mod is a Nim keyword please use `zmod` when you need GLSL `mod` behavior. + +## Coordinate System + +Right-hand z-forward coordinate system + +This is the same system used in the GLTF file format. + +> glTF uses a right-handed coordinate system. +> glTF defines +Y as up, +Z as forward, and -X as right; +> the front of a glTF asset faces +Z. + +[glTF Spec 2.0](https://registry.khronos.org/glTF/specs/2.0/glTF-2.0.html#coordinate-system-and-units) + +## OpenGL matrix column-major notation. + +> [9.005](https://www.opengl.org/archives/resources/faq/technical/transformations.htm) For programming purposes, OpenGL matrices are 16-value arrays with base vectors laid out contiguously in memory. The translation components occupy the 13th, 14th, and 15th elements of the 16-element matrix, where indices are numbered from 1 to 16 as described in section 2.11.2 of the [OpenGL 2.1 Specification](https://registry.khronos.org/OpenGL/specs/gl/glspec21.pdf). +> +> Sadly, the use of column-major format in the spec and blue book has resulted in endless confusion in the OpenGL programming community. Column-major notation suggests that matrices are not laid out in memory as a programmer would expect. + +OpenGL/GLSL/vmath vs Math/Specification notation: +``` + mat4([ + a, b, c, 0, | a d g x | + d, e, f, 0, | b e h y | + g, h, i, 0, | c f i z | + x, y, z, 1 | 0 0 0 1 | + ]) +``` + +# 1.x.x to 2.0.0 vmath breaking changes: +* New right-hand-z-forward cordate system and functions that care about +coordinate system where moved there. +* deprecated `lookAt()` please use `toAngles()`/`fromAngles()` instead. +* deprecated `fractional()` use `frac()` instead. + # 0.x.x to 1.0.0 vmath breaking changes: * `vec3(v)` no longer works please use `vec3(v.x, v.y, 0)` instead. diff --git a/src/vmath.nim b/src/vmath.nim index 85c9320..7431e7d 100644 --- a/src/vmath.nim +++ b/src/vmath.nim @@ -30,6 +30,8 @@ float32 float Vec2 Vec3 Vec4 Mat3 Mat4 Quat float64 double DVec2 DVec3 DVec4 DMat3 DMat4 DQuat ======= ====== ===== ===== ===== ===== ===== ===== + + ]## import macros, math, strutils @@ -406,13 +408,17 @@ proc quantize*[T: SomeFloat](v, n: T): T = ## Makes v be multiple of n. Rounding to integer quantize by 1.0. trunc(v / n) * n -proc fractional*[T: SomeFloat](v: T): T = +proc frac*[T: SomeFloat](v: T): T = ## Returns fractional part of a number. ## 3.14 -> 0.14 ## -3.14 -> 0.14 result = abs(v) result = result - trunc(result) +proc fractional*[T: SomeFloat](v: T): T {.deprecated: "Use frac() insetad"} = + ## Returns fractional part of a number. + frac(v) + proc inversesqrt*[T: float32|float64](v: T): T = ## Returns inverse square root. 1/sqrt(v) @@ -425,11 +431,11 @@ proc mix*[T: SomeFloat](a, b, v: T): T = v * (b - a) + a proc fixAngle*[T: SomeFloat](angle: T): T = - ## Make angle be from -PI to PI radians. + ## Normalize the angle be from -PI to PI radians. result = angle while result > PI: result -= PI * 2 - while result < -PI: + while result <= -PI: result += PI * 2 proc angleBetween*[T: SomeFloat](a, b: T): T = @@ -725,6 +731,11 @@ genMathFn(sqrt) genMathFn(floor) genMathFn(ceil) genMathFn(abs) +genMathFn(trunc) +genMathFn(frac) +genMathFn(quantize) +genMathFn(toRadians) +genMathFn(toDegrees) template genBoolFn(fn, op: untyped) = proc fn*[T](a, b: GVec2[T]): BVec2 = @@ -970,10 +981,42 @@ proc `pos=`*[T](a: var GMat3[T], pos: GVec2[T]) = a[2, 0] = pos.x a[2, 1] = pos.y +proc forward*[T](a: GMat4[T]): GVec3[T] {.inline.} = + ## Vector facing +Z. + result.x = a[2, 0] + result.y = a[2, 1] + result.z = a[2, 2] + +proc back*[T](a: GMat4[T]): GVec3[T] {.inline.} = + ## Vector facing -Z. + -a.forward() + +proc left*[T](a: GMat4[T]): GVec3[T] {.inline.} = + ## Vector facing +X. + result.x = a[0, 0] + result.y = a[0, 1] + result.z = a[0, 2] + +proc right*[T](a: GMat4[T]): GVec3[T] {.inline.} = + ## Vector facing -X. + -a.left() + +proc up*[T](a: GMat4[T]): GVec3[T] {.inline.} = + ## Vector facing +Y. + result.x = a[1, 0] + result.y = a[1, 1] + result.z = a[1, 2] + +proc down*[T](a: GMat4[T]): GVec3[T] {.inline.} = + ## Vector facing -X. + -a.up() + proc pos*[T](a: GMat4[T]): GVec3[T] = + ## Position of the matrix. gvec3[T](a[3].x, a[3].y, a[3].z) proc `pos=`*[T](a: var GMat4[T], pos: GVec3[T]) = + ## See the position of the matrix. a[3, 0] = pos.x a[3, 1] = pos.y a[3, 2] = pos.z @@ -1244,7 +1287,7 @@ proc translate*[T](v: GVec3[T]): GMat4[T] = ) proc rotate*[T](angle: T): GMat3[T] = - ## Create a rotation matrix by an angle. + ## Create a 2d rotation matrix by an angle. let sin = sin(angle) cos = cos(angle) @@ -1254,22 +1297,119 @@ proc rotate*[T](angle: T): GMat3[T] = 0, 0, 1 ) -proc hrp*[T](m: GMat4[T]): GVec3[T] = - ## Return heading, rotation and pivot of a matrix. - var heading, pitch, roll: float32 - if m[1] > 0.998: # singularity at north pole - heading = arctan2(m[2], m[10]) - pitch = PI / 2 - roll = 0 - elif m[1] < -0.998: # singularity at south pole - heading = arctan2(m[2], m[10]) - pitch = -PI / 2 - roll = 0 +proc rotationOnly*[T](a: GMat4[T]): GMat4[T] {.inline.} = + ## Clears the positional component and returns rotation only. + ## Assumes matrix has not been scaled. + result = a + result.pos = gvec3(0, 0, 0) + +proc rotateX*[T](angle: T): GMat4[T] = + ## Return a rotation matrix around X with angle. + result[0, 0] = 1 + result[0, 1] = 0 + result[0, 2] = 0 + result[0, 3] = 0 + + result[1, 0] = 0 + result[1, 1] = cos(angle) + result[1, 2] = -sin(angle) + result[1, 3] = 0 + + result[2, 0] = 0 + result[2, 1] = sin(angle) + result[2, 2] = cos(angle) + result[2, 3] = 0 + + result[3, 0] = 0 + result[3, 1] = 0 + result[3, 2] = 0 + result[3, 3] = 1 + +proc rotateY*[T](angle: T): GMat4[T] = + ## Return a rotation matrix around Y with angle. + result[0, 0] = cos(angle) + result[0, 1] = 0 + result[0, 2] = sin(angle) + result[0, 3] = 0 + + result[1, 0] = 0 + result[1, 1] = 1 + result[1, 2] = 0 + result[1, 3] = 0 + + result[2, 0] = -sin(angle) + result[2, 1] = 0 + result[2, 2] = cos(angle) + result[2, 3] = 0 + + result[3, 0] = 0 + result[3, 1] = 0 + result[3, 2] = 0 + result[3, 3] = 1 + +proc rotateZ*[T](angle: T): GMat4[T] = + ## Return a rotation matrix around Z with angle. + result[0, 0] = cos(angle) + result[0, 1] = -sin(angle) + result[0, 2] = 0 + result[0, 3] = 0 + + result[1, 0] = sin(angle) + result[1, 1] = cos(angle) + result[1, 2] = 0 + result[1, 3] = 0 + + result[2, 0] = 0 + result[2, 1] = 0 + result[2, 2] = 1 + result[2, 3] = 0 + + result[3, 0] = 0 + result[3, 1] = 0 + result[3, 2] = 0 + result[3, 3] = 1 + +proc toAngles*[T](a: GVec3[T]): GVec3[T] = + ## Given a 3d vector, computes euler angles: pitch and yaw + ## pitch (x rotation) + ## yaw (y rotation) + ## roll (z rotation) - always 0 in vector case + if a == vec3(0, 0, 0): + return + let + yaw = -arctan2(a.x, a.z) + pitch = -arctan2(sqrt(a.x*a.x + a.z*a.z), a.y) + T(PI/2) + result.x = pitch.fixAngle + result.y = yaw.fixAngle + +proc toAngles*[T](origin, target: GVec3[T]): GVec3[T] = + ## Gives euler angles from origin to target + ## pitch (x rotation) + ## yaw (y rotation) + ## roll (z rotation) - always 0 in vector case + toAngles(target - origin) + +proc toAngles*[T](m: GMat4[T]): GVec3[T] = + ## Decomposes the matrix into euler angles: + ## pitch (x rotation) + ## yaw (y rotation) + ## roll (z rotation) + ## Assumes matrix has not been scaled. + result.x = arcsin(m[2,1]) + if result.x > PI/2: + # Degenerate case over north pole. + result.y = arctan2(m[0, 2], m[0, 0]) + elif result.x < -PI/2: + # Degenerate case over south pole. + result.y = arctan2(m[0, 2], m[0, 0]) else: - heading = arctan2(-m[8], m[0]) - pitch = arctan2(-m[6], m[5]) - roll = arcsin(m[4]) - gvec3[T](heading, pitch, roll) + # Normal case. + result.y = -arctan2(m[2, 0], m[2, 2]) + result.z = -arctan2(m[0, 1], m[1, 1]) + +proc fromAngles*[T](a: GVec3[T]): GMat4[T] = + ## Takes a vector containing euler angles and returns a matrix. + rotateY(a.y) * rotateX(a.x) * rotateZ(a.z) proc frustum*[T](left, right, bottom, top, near, far: T): GMat4[T] = ## Create a frustum matrix. @@ -1332,7 +1472,10 @@ proc ortho*[T](left, right, bottom, top, near, far: T): GMat4[T] = result[3, 2] = T(-(far + near) / fn) result[3, 3] = 1 -proc lookAt*[T](eye, center, up: GVec3[T]): GMat4[T] = +proc lookAt*[T](eye, center, up: GVec3[T]): GMat4[T] + {.deprecated: "Wrong coordinate system. " & + "Use toAngles(eye, center).fromAngles() instead to get " & + "right-handed-z-forward coordinate system".} = ## Create a matrix that would convert eye pos to looking at center. let eyex = eye[0] @@ -1413,7 +1556,10 @@ proc lookAt*[T](eye, center, up: GVec3[T]): GMat4[T] = result[3, 2] = -(z0 * eyex + z1 * eyey + z2 * eyez) result[3, 3] = 1 -proc lookAt*[T](eye, center: GVec3[T]): GMat4[T] = +proc lookAt*[T](eye, center: GVec3[T]): GMat4[T] + {.deprecated: "Wrong coordinate system. " & + "Use toAngles(eye, center).fromAngles() instead to get " & + "right-handed-z-forward coordinate system".} = ## Look center from eye with default UP vector. lookAt(eye, center, gvec3(T(0), 0, 1)) @@ -1598,17 +1744,6 @@ proc rotate*[T](angle: T, axis: GVec3[T]): GMat4[T] = ## Return a rotation matrix with axis and angle. fromAxisAngle(axis, angle).mat4() -proc rotateX*[T](angle: T): GMat4[T] = - ## Return a rotation matrix around X with angle. - fromAxisAngle(gvec3[T](1, 0, 0), angle).mat4() - -proc rotateY*[T](angle: T): GMat4[T] = - ## Return a rotation matrix around Y with angle. - fromAxisAngle(gvec3[T](0, 1, 0), angle).mat4() - -proc rotateZ*[T](angle: T): GMat4[T] = - ## Return a rotation matrix around Z with angle. - fromAxisAngle(gvec3[T](0, 0, 1), angle).mat4() when defined(release): {.pop.} diff --git a/tests/test.nim b/tests/test.nim index e7de428..bb89ad9 100644 --- a/tests/test.nim +++ b/tests/test.nim @@ -863,29 +863,7 @@ block: ) block: - # 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) - - let - a = lookAt(vec3(1, 2, 3), vec3(0, 0, 0)) - b = lookAt(dvec3(1, 2, 3), dvec3(0, 0, 0)) - + # test quat and matrix doAssert ortho[float32](-1, 1, 1, -1, -1000, 1000) ~= mat4( 1.0, 0.0, 0.0, 0.0, 0.0, -1.0, 0.0, 0.0, @@ -1045,4 +1023,136 @@ block: b = a / 2 when compiles(b = a div 2): doAssert false # type mismatch +proc closeAngles(a, b: Vec3): bool = + const epsilon = 0.001 + return abs(angleBetween(a.x, b.x)) < epsilon and + abs(angleBetween(a.y, b.y)) < epsilon and + abs(angleBetween(a.z, b.z)) < epsilon + +const PI = PI.float32 + +block: + # test Euler angles from a vector + doAssert vec3(0, 0, 0).toAngles.closeAngles vec3(0f, 0f, 0f) + doAssert vec3(0, 0, 1).toAngles.closeAngles vec3(0f, 0f, 0f) # forward + doAssert vec3(0, 0, -1).toAngles.closeAngles vec3(0f, PI, 0f) # back + doAssert vec3(-1, 0, 0).toAngles.closeAngles vec3(0f, PI/2, 0f) # right + doAssert vec3(1, 0, 0).toAngles.closeAngles vec3(0f, -PI/2, 0f) # left + doAssert vec3(0, 1, 0).toAngles.closeAngles vec3(PI/2, 0f, 0f) # up + doAssert vec3(0, -1, 0).toAngles.closeAngles vec3(-PI/2, 0f, 0f) # down + +block: + # test Euler angles from a matrix + doAssert translate(vec3(0, 0, 0)).toAngles.closeAngles vec3(0f, 0f, 0f) + doAssert rotateX(0f).toAngles.closeAngles vec3(0f, 0f, 0f) # forward + doAssert rotateY(PI).toAngles.closeAngles vec3(0f, -PI, 0f) # back + doAssert rotateY(PI/2).toAngles.closeAngles vec3(0f, PI/2, 0f) # back + doAssert rotateY(-PI/2).toAngles.closeAngles vec3(0f, -PI/2, 0f) # back + doAssert rotateX(PI/2).toAngles.closeAngles vec3(PI/2, 0f, 0f) # up + doAssert rotateX(-PI/2).toAngles.closeAngles vec3(-PI/2, 0f, 0f) # down + doAssert rotateZ(PI/2).toAngles.closeAngles vec3(0f, 0f, PI/2) # tilt right + doAssert rotateZ(-PI/2).toAngles.closeAngles vec3(0f, 0f, -PI/2) # tilt left + + doAssert Mat4().toAngles.closeAngles vec3(0, 0, 0) + + doAssert rotateX(10.toRadians()).toAngles.closeAngles vec3(10.toRadians(), 0, 0) + doAssert rotateY(10.toRadians()).toAngles.closeAngles vec3(0, 10.toRadians(), 0) + doAssert rotateZ(10.toRadians()).toAngles.closeAngles vec3(0, 0, 10.toRadians()) + doAssert rotateX(89.toRadians()).toAngles.closeAngles vec3(89.toRadians(), 0, 0) + doAssert rotateY(89.toRadians()).toAngles.closeAngles vec3(0, 89.toRadians(), 0) + doAssert rotateZ(89.toRadians()).toAngles.closeAngles vec3(0, 0, 89.toRadians()) + doAssert rotateX(90.toRadians()).toAngles.closeAngles vec3(90.toRadians(), 0, 0) + doAssert rotateY(90.toRadians()).toAngles.closeAngles vec3(0, 90.toRadians(), 0) + doAssert rotateZ(90.toRadians()).toAngles.closeAngles vec3(0, 0, 90.toRadians()) + doAssert rotateX(90.toRadians()).toAngles.closeAngles vec3(90.toRadians(), 0, 0) + doAssert rotateY(90.toRadians()).toAngles.closeAngles vec3(0, 90.toRadians(), 0) + doAssert rotateZ(-90.toRadians()).toAngles.closeAngles vec3(0, 0, -90.toRadians()) + doAssert rotateY(180.toRadians()).toAngles.closeAngles vec3(0, -180.toRadians(), 0) + doAssert rotateZ(180.toRadians()).toAngles.closeAngles vec3(0, 0, 180.toRadians()) + doAssert rotateY(-180.toRadians()).toAngles.closeAngles vec3(0, 180.toRadians(), 0) + doAssert rotateZ(-180.toRadians()).toAngles.closeAngles vec3(0, 0, 180.toRadians()) + +block: + # Euler angles fuzzing tests. + + # Test fromAngles with and without roll have same forward + for i in 0 .. 1000: + let + xr = rand(-89.9f .. 89.9f).toRadians + yr = rand(-180 .. 180).toRadians + zr = rand(-180 .. 180).toRadians + a = vec3(xr, yr, zr) + b = vec3(xr, yr, 0f) + ma = fromAngles(a) + mb = fromAngles(b) + + doAssert ma.forward() ~= mb.forward() + + # Test forward/back, right/left, up/down combos + for i in 0 .. 1000: + let + xr = rand(-89.9f .. 89.9f).toRadians + yr = rand(-180 .. 180).toRadians + zr = rand(-180 .. 180).toRadians + b = vec3(xr, yr, zr) + m = fromAngles(b) + + doAssert m.forward() ~= m * vec3(0, 0, 1) + doAssert m.back() ~= m * vec3(0, 0, -1) + + doAssert m.right() ~= m * vec3(-1, 0, 0) + doAssert m.left() ~= m * vec3(1, 0, 0) + + doAssert m.up() ~= m * vec3(0, 1, 0) + doAssert m.down() ~= m * vec3(0, -1, 0) + + # Test non-polar and non-rotated cases + for i in 0 .. 1000: + let + xr = rand(-89.9f .. 89.9f).toRadians + yr = rand(-180 .. 180).toRadians + zr = 0f + b = vec3(xr, yr, zr) + m = fromAngles(b) + a = m.toAngles() + doAssert a.closeAngles(b) + + # Test non-polar cases + for i in 0 .. 1000: + let + xr = rand(-89.9f .. 89.9f).toRadians + yr = rand(-180 .. 180).toRadians + zr = rand(-180 .. 180).toRadians + b = vec3(xr, yr, zr) + m = fromAngles(b) + a = m.toAngles() + doAssert a.closeAngles(b) + + # Test polar and non-rotated cases + for i in 0 .. 1000: + let + xr = sample([-90, 90]).toRadians + yr = rand(-180 .. 180).toRadians + zr = 0f + b = vec3(xr, yr, zr) + m = fromAngles(b) + a = m.toAngles() + doAssert a.closeAngles(b) + + # Test polar and crazy rotated cases + for i in 0 .. 1000: + let + xr = sample([-90, 90]).toRadians + yr = rand(-180 .. 180).toRadians + zr = rand(-180 .. 180).toRadians + b = vec3(xr, yr, zr) + m = fromAngles(b) + a = m.toAngles() + + doAssert abs(angleBetween(a.x, b.x)) < 0.001 + if xr > 0: + doAssert abs(angleBetween(a.y, b.y + b.z)) < 0.001 + else: + doAssert abs(angleBetween(a.y, b.y - b.z)) < 0.001 + echo "test finished successfully" From e4364449e8efb9b4e52595ede5a8ea73b990e2e9 Mon Sep 17 00:00:00 2001 From: treeform Date: Sat, 4 Mar 2023 14:19:42 -0800 Subject: [PATCH 02/11] Fix warnings. --- src/vmath.nim | 32 +++++++++++++++----------------- tests/test.nim | 24 ++++++++++++------------ 2 files changed, 27 insertions(+), 29 deletions(-) diff --git a/src/vmath.nim b/src/vmath.nim index 7431e7d..1615220 100644 --- a/src/vmath.nim +++ b/src/vmath.nim @@ -30,8 +30,6 @@ float32 float Vec2 Vec3 Vec4 Mat3 Mat4 Quat float64 double DVec2 DVec3 DVec4 DMat3 DMat4 DQuat ======= ====== ===== ===== ===== ===== ===== ===== - - ]## import macros, math, strutils @@ -423,26 +421,26 @@ proc inversesqrt*[T: float32|float64](v: T): T = ## Returns inverse square root. 1/sqrt(v) -proc mix*[T: SomeFloat](a, b, v: T): T = +proc mix*[T](a, b, v: T): T = ## Interpolates value between a and b. ## * 0 -> a ## * 1 -> b ## * 0.5 -> between a and b v * (b - a) + a -proc fixAngle*[T: SomeFloat](angle: T): T = - ## Normalize the angle be from -PI to PI radians. +proc fixAngle*[T](angle: T): T = + ## Normalize the angle to be from -PI to PI radians. result = angle - while result > PI: - result -= PI * 2 - while result <= -PI: - result += PI * 2 + while result > T(PI): + result -= T(PI) * 2 + while result <= -T(PI): + result += T(PI) * 2 -proc angleBetween*[T: SomeFloat](a, b: T): T = +proc angleBetween*[T](a, b: T): T = ## Angle between angle a and angle b. fixAngle(b - a) -proc turnAngle*[T: SomeFloat](a, b, speed: T): T = +proc turnAngle*[T](a, b, speed: T): T = ## Move from angle a to angle b with step of v. var turn = fixAngle(b - a) @@ -1370,11 +1368,11 @@ proc rotateZ*[T](angle: T): GMat4[T] = result[3, 3] = 1 proc toAngles*[T](a: GVec3[T]): GVec3[T] = - ## Given a 3d vector, computes euler angles: pitch and yaw + ## Given a 3d vector, computes Euler angles: pitch and yaw ## pitch (x rotation) ## yaw (y rotation) ## roll (z rotation) - always 0 in vector case - if a == vec3(0, 0, 0): + if a == gvec3[T](T(0), T(0), T(0)): return let yaw = -arctan2(a.x, a.z) @@ -1383,14 +1381,14 @@ proc toAngles*[T](a: GVec3[T]): GVec3[T] = result.y = yaw.fixAngle proc toAngles*[T](origin, target: GVec3[T]): GVec3[T] = - ## Gives euler angles from origin to target + ## Gives Euler angles from origin to target ## pitch (x rotation) ## yaw (y rotation) ## roll (z rotation) - always 0 in vector case toAngles(target - origin) proc toAngles*[T](m: GMat4[T]): GVec3[T] = - ## Decomposes the matrix into euler angles: + ## Decomposes the matrix into Euler angles: ## pitch (x rotation) ## yaw (y rotation) ## roll (z rotation) @@ -1408,7 +1406,7 @@ proc toAngles*[T](m: GMat4[T]): GVec3[T] = result.z = -arctan2(m[0, 1], m[1, 1]) proc fromAngles*[T](a: GVec3[T]): GMat4[T] = - ## Takes a vector containing euler angles and returns a matrix. + ## Takes a vector containing Euler angles and returns a matrix. rotateY(a.y) * rotateX(a.x) * rotateZ(a.z) proc frustum*[T](left, right, bottom, top, near, far: T): GMat4[T] = @@ -1583,7 +1581,7 @@ type template genQuatConstructor*(lower, upper, typ: untyped) = ## Generate quaternion constructor for your own type. - proc `lower`*(): `upper` = gvec4[typ](0, 0, 0, 1) + proc `lower`*(): `upper` = gvec4[typ](typ(0), typ(0), typ(0), typ(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` = diff --git a/tests/test.nim b/tests/test.nim index bb89ad9..7c6e49e 100644 --- a/tests/test.nim +++ b/tests/test.nim @@ -53,18 +53,18 @@ block: doAssert quantize(1.23456789, 0.01) ~= 1.23 doAssert quantize(-1.23456789, 0.01) ~= -1.23 - doAssert fractional(0.0) ~= 0.0 - doAssert fractional(3.14) ~= 0.14 - doAssert fractional(-3.14) ~= 0.14 - doAssert fractional(1.23456789) ~= 0.23456789 - doAssert fractional(-1.23456789) ~= 0.23456789 + doAssert frac(0.0) ~= 0.0 + doAssert frac(3.14) ~= 0.14 + doAssert frac(-3.14) ~= 0.14 + doAssert frac(1.23456789) ~= 0.23456789 + doAssert frac(-1.23456789) ~= 0.23456789 - doAssert lerp(0.0, 1.0, 0.5) ~= 0.5 - doAssert lerp(0.0, 10.0, 0.5) ~= 5.0 - doAssert lerp(0.0, 100.0, 0.5) ~= 50.0 - doAssert lerp(-1.0, 1.0, 0.25) ~= -0.5 - doAssert lerp(-10.0, 10.0, 0.25) ~= -5.0 - doAssert lerp(-100.0, 100.0, 0.25) ~= -50.0 + doAssert mix(0.0, 1.0, 0.5) ~= 0.5 + doAssert mix(0.0, 10.0, 0.5) ~= 5.0 + doAssert mix(0.0, 100.0, 0.5) ~= 50.0 + doAssert mix(-1.0, 1.0, 0.25) ~= -0.5 + doAssert mix(-10.0, 10.0, 0.25) ~= -5.0 + doAssert mix(-100.0, 100.0, 0.25) ~= -50.0 doAssert mix(0.0, 1.0, 0.5) ~= 0.5 doAssert mix(0.0, 10.0, 0.5) ~= 5.0 @@ -1053,7 +1053,7 @@ block: doAssert rotateZ(PI/2).toAngles.closeAngles vec3(0f, 0f, PI/2) # tilt right doAssert rotateZ(-PI/2).toAngles.closeAngles vec3(0f, 0f, -PI/2) # tilt left - doAssert Mat4().toAngles.closeAngles vec3(0, 0, 0) + doAssert mat4().toAngles.closeAngles vec3(0, 0, 0) doAssert rotateX(10.toRadians()).toAngles.closeAngles vec3(10.toRadians(), 0, 0) doAssert rotateY(10.toRadians()).toAngles.closeAngles vec3(0, 10.toRadians(), 0) From 76ea02c0d70b14dd8bb11a8cf136a4cc6f4b2e1e Mon Sep 17 00:00:00 2001 From: treeform Date: Sat, 4 Mar 2023 14:34:53 -0800 Subject: [PATCH 03/11] better build --- .github/workflows/build.yml | 3 ++ tests/test.nim | 74 ++++++++++++++++++------------------- 2 files changed, 40 insertions(+), 37 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 2830b81..722e23b 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -12,6 +12,9 @@ jobs: steps: - uses: actions/checkout@v2 - uses: jiro4989/setup-nim-action@v1 + with: + nim-version: ${{ matrix.nim-version }} + repo-token: ${{ secrets.GITHUB_TOKEN }} - run: nimble test -y - run: nimble test --gc:orc -y - run: nimble test -y -d:vmathObjBased diff --git a/tests/test.nim b/tests/test.nim index 7c6e49e..4d211b5 100644 --- a/tests/test.nim +++ b/tests/test.nim @@ -1023,7 +1023,7 @@ block: b = a / 2 when compiles(b = a div 2): doAssert false # type mismatch -proc closeAngles(a, b: Vec3): bool = +proc eq(a, b: Vec3): bool = const epsilon = 0.001 return abs(angleBetween(a.x, b.x)) < epsilon and abs(angleBetween(a.y, b.y)) < epsilon and @@ -1033,44 +1033,44 @@ const PI = PI.float32 block: # test Euler angles from a vector - doAssert vec3(0, 0, 0).toAngles.closeAngles vec3(0f, 0f, 0f) - doAssert vec3(0, 0, 1).toAngles.closeAngles vec3(0f, 0f, 0f) # forward - doAssert vec3(0, 0, -1).toAngles.closeAngles vec3(0f, PI, 0f) # back - doAssert vec3(-1, 0, 0).toAngles.closeAngles vec3(0f, PI/2, 0f) # right - doAssert vec3(1, 0, 0).toAngles.closeAngles vec3(0f, -PI/2, 0f) # left - doAssert vec3(0, 1, 0).toAngles.closeAngles vec3(PI/2, 0f, 0f) # up - doAssert vec3(0, -1, 0).toAngles.closeAngles vec3(-PI/2, 0f, 0f) # down + doAssert vec3(0, 0, 0).toAngles.eq vec3(0f, 0f, 0f) + doAssert vec3(0, 0, 1).toAngles.eq vec3(0f, 0f, 0f) # forward + doAssert vec3(0, 0, -1).toAngles.eq vec3(0f, PI, 0f) # back + doAssert vec3(-1, 0, 0).toAngles.eq vec3(0f, PI/2, 0f) # right + doAssert vec3(1, 0, 0).toAngles.eq vec3(0f, -PI/2, 0f) # left + doAssert vec3(0, 1, 0).toAngles.eq vec3(PI/2, 0f, 0f) # up + doAssert vec3(0, -1, 0).toAngles.eq vec3(-PI/2, 0f, 0f) # down block: # test Euler angles from a matrix - doAssert translate(vec3(0, 0, 0)).toAngles.closeAngles vec3(0f, 0f, 0f) - doAssert rotateX(0f).toAngles.closeAngles vec3(0f, 0f, 0f) # forward - doAssert rotateY(PI).toAngles.closeAngles vec3(0f, -PI, 0f) # back - doAssert rotateY(PI/2).toAngles.closeAngles vec3(0f, PI/2, 0f) # back - doAssert rotateY(-PI/2).toAngles.closeAngles vec3(0f, -PI/2, 0f) # back - doAssert rotateX(PI/2).toAngles.closeAngles vec3(PI/2, 0f, 0f) # up - doAssert rotateX(-PI/2).toAngles.closeAngles vec3(-PI/2, 0f, 0f) # down - doAssert rotateZ(PI/2).toAngles.closeAngles vec3(0f, 0f, PI/2) # tilt right - doAssert rotateZ(-PI/2).toAngles.closeAngles vec3(0f, 0f, -PI/2) # tilt left + doAssert translate(vec3(0, 0, 0)).toAngles.eq vec3(0f, 0f, 0f) + doAssert rotateX(0f).toAngles.eq vec3(0f, 0f, 0f) # forward + doAssert rotateY(PI).toAngles.eq vec3(0f, -PI, 0f) # back + doAssert rotateY(PI/2).toAngles.eq vec3(0f, PI/2, 0f) # back + doAssert rotateY(-PI/2).toAngles.eq vec3(0f, -PI/2, 0f) # back + doAssert rotateX(PI/2).toAngles.eq vec3(PI/2, 0f, 0f) # up + doAssert rotateX(-PI/2).toAngles.eq vec3(-PI/2, 0f, 0f) # down + doAssert rotateZ(PI/2).toAngles.eq vec3(0f, 0f, PI/2) # tilt right + doAssert rotateZ(-PI/2).toAngles.eq vec3(0f, 0f, -PI/2) # tilt left - doAssert mat4().toAngles.closeAngles vec3(0, 0, 0) + doAssert mat4().toAngles.eq vec3(0, 0, 0) - doAssert rotateX(10.toRadians()).toAngles.closeAngles vec3(10.toRadians(), 0, 0) - doAssert rotateY(10.toRadians()).toAngles.closeAngles vec3(0, 10.toRadians(), 0) - doAssert rotateZ(10.toRadians()).toAngles.closeAngles vec3(0, 0, 10.toRadians()) - doAssert rotateX(89.toRadians()).toAngles.closeAngles vec3(89.toRadians(), 0, 0) - doAssert rotateY(89.toRadians()).toAngles.closeAngles vec3(0, 89.toRadians(), 0) - doAssert rotateZ(89.toRadians()).toAngles.closeAngles vec3(0, 0, 89.toRadians()) - doAssert rotateX(90.toRadians()).toAngles.closeAngles vec3(90.toRadians(), 0, 0) - doAssert rotateY(90.toRadians()).toAngles.closeAngles vec3(0, 90.toRadians(), 0) - doAssert rotateZ(90.toRadians()).toAngles.closeAngles vec3(0, 0, 90.toRadians()) - doAssert rotateX(90.toRadians()).toAngles.closeAngles vec3(90.toRadians(), 0, 0) - doAssert rotateY(90.toRadians()).toAngles.closeAngles vec3(0, 90.toRadians(), 0) - doAssert rotateZ(-90.toRadians()).toAngles.closeAngles vec3(0, 0, -90.toRadians()) - doAssert rotateY(180.toRadians()).toAngles.closeAngles vec3(0, -180.toRadians(), 0) - doAssert rotateZ(180.toRadians()).toAngles.closeAngles vec3(0, 0, 180.toRadians()) - doAssert rotateY(-180.toRadians()).toAngles.closeAngles vec3(0, 180.toRadians(), 0) - doAssert rotateZ(-180.toRadians()).toAngles.closeAngles vec3(0, 0, 180.toRadians()) + doAssert rotateX(10.toRadians()).toAngles.eq vec3(10.toRadians(), 0, 0) + doAssert rotateY(10.toRadians()).toAngles.eq vec3(0, 10.toRadians(), 0) + doAssert rotateZ(10.toRadians()).toAngles.eq vec3(0, 0, 10.toRadians()) + doAssert rotateX(89.toRadians()).toAngles.eq vec3(89.toRadians(), 0, 0) + doAssert rotateY(89.toRadians()).toAngles.eq vec3(0, 89.toRadians(), 0) + doAssert rotateZ(89.toRadians()).toAngles.eq vec3(0, 0, 89.toRadians()) + doAssert rotateX(90.toRadians()).toAngles.eq vec3(90.toRadians(), 0, 0) + doAssert rotateY(90.toRadians()).toAngles.eq vec3(0, 90.toRadians(), 0) + doAssert rotateZ(90.toRadians()).toAngles.eq vec3(0, 0, 90.toRadians()) + doAssert rotateX(90.toRadians()).toAngles.eq vec3(90.toRadians(), 0, 0) + doAssert rotateY(90.toRadians()).toAngles.eq vec3(0, 90.toRadians(), 0) + doAssert rotateZ(-90.toRadians()).toAngles.eq vec3(0, 0, -90.toRadians()) + doAssert rotateY(180.toRadians()).toAngles.eq vec3(0, -180.toRadians(), 0) + doAssert rotateZ(180.toRadians()).toAngles.eq vec3(0, 0, 180.toRadians()) + doAssert rotateY(-180.toRadians()).toAngles.eq vec3(0, 180.toRadians(), 0) + doAssert rotateZ(-180.toRadians()).toAngles.eq vec3(0, 0, 180.toRadians()) block: # Euler angles fuzzing tests. @@ -1115,7 +1115,7 @@ block: b = vec3(xr, yr, zr) m = fromAngles(b) a = m.toAngles() - doAssert a.closeAngles(b) + doAssert a.eq(b) # Test non-polar cases for i in 0 .. 1000: @@ -1126,7 +1126,7 @@ block: b = vec3(xr, yr, zr) m = fromAngles(b) a = m.toAngles() - doAssert a.closeAngles(b) + doAssert a.eq(b) # Test polar and non-rotated cases for i in 0 .. 1000: @@ -1137,7 +1137,7 @@ block: b = vec3(xr, yr, zr) m = fromAngles(b) a = m.toAngles() - doAssert a.closeAngles(b) + doAssert a.eq(b) # Test polar and crazy rotated cases for i in 0 .. 1000: From 72f0a1f7d5b3605dcbdcc0ef2577bc8a9bd38b33 Mon Sep 17 00:00:00 2001 From: treeform Date: Sat, 4 Mar 2023 16:39:12 -0800 Subject: [PATCH 04/11] test more versions --- .github/workflows/build.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 722e23b..9c01be1 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -6,6 +6,7 @@ jobs: fail-fast: false matrix: os: [ubuntu-latest, windows-latest] + nim-version: ['1.4.0', '1.4.x', 'stable'] runs-on: ${{ matrix.os }} From f84453543ad4f3779712ca288d3ea8685767767a Mon Sep 17 00:00:00 2001 From: treeform Date: Sat, 4 Mar 2023 17:18:17 -0800 Subject: [PATCH 05/11] undo fixed point stuff, its not working --- src/vmath.nim | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/src/vmath.nim b/src/vmath.nim index 1615220..ed923f1 100644 --- a/src/vmath.nim +++ b/src/vmath.nim @@ -421,26 +421,26 @@ proc inversesqrt*[T: float32|float64](v: T): T = ## Returns inverse square root. 1/sqrt(v) -proc mix*[T](a, b, v: T): T = +proc mix*[T: SomeFloat](a, b, v: T): T = ## Interpolates value between a and b. ## * 0 -> a ## * 1 -> b ## * 0.5 -> between a and b v * (b - a) + a -proc fixAngle*[T](angle: T): T = +proc fixAngle*[T: SomeFloat](angle: T): T = ## Normalize the angle to be from -PI to PI radians. result = angle - while result > T(PI): - result -= T(PI) * 2 - while result <= -T(PI): - result += T(PI) * 2 + while result > PI: + result -= PI * 2 + while result <= -PI: + result += PI * 2 -proc angleBetween*[T](a, b: T): T = +proc angleBetween*[T: SomeFloat](a, b: T): T = ## Angle between angle a and angle b. fixAngle(b - a) -proc turnAngle*[T](a, b, speed: T): T = +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) @@ -1581,7 +1581,7 @@ type template genQuatConstructor*(lower, upper, typ: untyped) = ## Generate quaternion constructor for your own type. - proc `lower`*(): `upper` = gvec4[typ](typ(0), typ(0), typ(0), typ(1)) + 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` = From 6078b5156185c6fc518289f922e8602e0835289b Mon Sep 17 00:00:00 2001 From: treeform Date: Sun, 5 Mar 2023 11:41:13 -0800 Subject: [PATCH 06/11] fract not frac! --- src/vmath.nim | 6 +++--- tests/test.nim | 10 +++++----- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/src/vmath.nim b/src/vmath.nim index ed923f1..a3a7118 100644 --- a/src/vmath.nim +++ b/src/vmath.nim @@ -406,7 +406,7 @@ proc quantize*[T: SomeFloat](v, n: T): T = ## Makes v be multiple of n. Rounding to integer quantize by 1.0. trunc(v / n) * n -proc frac*[T: SomeFloat](v: T): T = +proc fract*[T: SomeFloat](v: T): T = ## Returns fractional part of a number. ## 3.14 -> 0.14 ## -3.14 -> 0.14 @@ -415,7 +415,7 @@ proc frac*[T: SomeFloat](v: T): T = proc fractional*[T: SomeFloat](v: T): T {.deprecated: "Use frac() insetad"} = ## Returns fractional part of a number. - frac(v) + fract(v) proc inversesqrt*[T: float32|float64](v: T): T = ## Returns inverse square root. @@ -730,7 +730,7 @@ genMathFn(floor) genMathFn(ceil) genMathFn(abs) genMathFn(trunc) -genMathFn(frac) +genMathFn(fract) genMathFn(quantize) genMathFn(toRadians) genMathFn(toDegrees) diff --git a/tests/test.nim b/tests/test.nim index 4d211b5..ffba8db 100644 --- a/tests/test.nim +++ b/tests/test.nim @@ -53,11 +53,11 @@ block: doAssert quantize(1.23456789, 0.01) ~= 1.23 doAssert quantize(-1.23456789, 0.01) ~= -1.23 - doAssert frac(0.0) ~= 0.0 - doAssert frac(3.14) ~= 0.14 - doAssert frac(-3.14) ~= 0.14 - doAssert frac(1.23456789) ~= 0.23456789 - doAssert frac(-1.23456789) ~= 0.23456789 + doAssert fract(0.0) ~= 0.0 + doAssert fract(3.14) ~= 0.14 + doAssert fract(-3.14) ~= 0.14 + doAssert fract(1.23456789) ~= 0.23456789 + doAssert fract(-1.23456789) ~= 0.23456789 doAssert mix(0.0, 1.0, 0.5) ~= 0.5 doAssert mix(0.0, 10.0, 0.5) ~= 5.0 From 00190ad7fb5d9f6e92478ed82b372153dad005d1 Mon Sep 17 00:00:00 2001 From: treeform Date: Mon, 8 May 2023 15:22:35 -0700 Subject: [PATCH 07/11] update github actions --- .github/workflows/build.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 9c01be1..a853593 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -11,7 +11,7 @@ jobs: runs-on: ${{ matrix.os }} steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v3 - uses: jiro4989/setup-nim-action@v1 with: nim-version: ${{ matrix.nim-version }} From 6e2906d9898fffe4edf18d77c10b32f09bcf8233 Mon Sep 17 00:00:00 2001 From: treeform Date: Wed, 10 May 2023 17:35:15 -0700 Subject: [PATCH 08/11] Switch to github action doc generator. --- .github/workflows/docs.yml | 26 ++++++++++++++++++++++++++ README.md | 2 +- 2 files changed, 27 insertions(+), 1 deletion(-) create mode 100644 .github/workflows/docs.yml diff --git a/.github/workflows/docs.yml b/.github/workflows/docs.yml new file mode 100644 index 0000000..683a6b5 --- /dev/null +++ b/.github/workflows/docs.yml @@ -0,0 +1,26 @@ +name: docs +on: + push: + branches: + - master +env: + nim-version: 'stable' + nim-src: src/${{ github.event.repository.name }}.nim + deploy-dir: .gh-pages +jobs: + docs: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v3 + - uses: jiro4989/setup-nim-action@v1 + with: + nim-version: ${{ env.nim-version }} + - run: nimble install -Y + - run: nimble doc --index:on --project --git.url:https://github.com/${{ github.repository }} --git.commit:master --out:${{ env.deploy-dir }} ${{ env.nim-src }} + - name: "Copy to index.html" + run: cp ${{ env.deploy-dir }}/${{ github.event.repository.name }}.html ${{ env.deploy-dir }}/index.html + - name: Deploy documents + uses: peaceiris/actions-gh-pages@v3 + with: + github_token: ${{ secrets.GITHUB_TOKEN }} + publish_dir: ${{ env.deploy-dir }} diff --git a/README.md b/README.md index fc55880..49a332c 100644 --- a/README.md +++ b/README.md @@ -6,7 +6,7 @@ ![Github Actions](https://github.com/treeform/vmath/workflows/Github%20Actions/badge.svg) -[API reference](https://nimdocs.com/treeform/vmath) +[API reference](https://treeform.github.io/vmath) This library has no dependencies other than the Nim standard library. From 8ff93d903a1898f17fa10ea13b56a2f9b6e9380c Mon Sep 17 00:00:00 2001 From: treeform Date: Thu, 11 May 2023 22:15:07 -0700 Subject: [PATCH 09/11] more changes --- README.md | 4 +++- src/vmath.nim | 56 ++++++++++++++++++++++++++++++++++++++++++--------- 2 files changed, 49 insertions(+), 11 deletions(-) diff --git a/README.md b/README.md index 49a332c..57fd69b 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ -# VMath - 2d and 3d vector math. +# VMath - 2D and 3D vector math. `nimble install vmath` @@ -10,6 +10,8 @@ This library has no dependencies other than the Nim standard library. +Supports c, cpp and js backend. + ## About Your one stop shop for vector math routines for 2d and 3d graphics. diff --git a/src/vmath.nim b/src/vmath.nim index a3a7118..438c150 100644 --- a/src/vmath.nim +++ b/src/vmath.nim @@ -1,22 +1,20 @@ ##[ -This library has no dependencies other than the Nim standard libarary. - Your one stop shop for vector math routines for 2d and 3d graphics. * Pure Nim with no dependencies. * Very similar to GLSL Shader Language with extra stuff. * Extensively benchmarked. -====== =========== =================================================== +====== =========== ================================================= 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 -====== =========== =================================================== +====== =========== ================================================= +BVec# bvec# vector of booleans +IVec# ivec# vector of signed integers +UVec# uvec# vector of unsigned integers +Vec# vec# vector of single-precision floating-point numbers +DVec# dvec# vector of double-precision floating-point numbers +====== =========== ================================================= You can use these constructors to make them: @@ -438,10 +436,12 @@ proc fixAngle*[T: SomeFloat](angle: T): T = proc angleBetween*[T: SomeFloat](a, b: T): T = ## Angle between angle a and angle b. + ## All angles assume radians. fixAngle(b - a) proc turnAngle*[T: SomeFloat](a, b, speed: T): T = ## Move from angle a to angle b with step of v. + ## All angles assume radians. var turn = fixAngle(b - a) if abs(turn) < speed: @@ -1285,7 +1285,12 @@ proc translate*[T](v: GVec3[T]): GMat4[T] = ) proc rotate*[T](angle: T): GMat3[T] = +<<<<<<< 6e2906d9898fffe4edf18d77c10b32f09bcf8233 ## Create a 2d rotation matrix by an angle. +======= + ## Create a 2D rotation matrix by an angle. + ## All angles assume radians. +>>>>>>> more changes let sin = sin(angle) cos = cos(angle) @@ -1303,6 +1308,10 @@ proc rotationOnly*[T](a: GMat4[T]): GMat4[T] {.inline.} = proc rotateX*[T](angle: T): GMat4[T] = ## Return a rotation matrix around X with angle. +<<<<<<< 6e2906d9898fffe4edf18d77c10b32f09bcf8233 +======= + ## All angles assume radians. +>>>>>>> more changes result[0, 0] = 1 result[0, 1] = 0 result[0, 2] = 0 @@ -1325,6 +1334,10 @@ proc rotateX*[T](angle: T): GMat4[T] = proc rotateY*[T](angle: T): GMat4[T] = ## Return a rotation matrix around Y with angle. +<<<<<<< 6e2906d9898fffe4edf18d77c10b32f09bcf8233 +======= + ## All angles assume radians. +>>>>>>> more changes result[0, 0] = cos(angle) result[0, 1] = 0 result[0, 2] = sin(angle) @@ -1347,6 +1360,10 @@ proc rotateY*[T](angle: T): GMat4[T] = proc rotateZ*[T](angle: T): GMat4[T] = ## Return a rotation matrix around Z with angle. +<<<<<<< 6e2906d9898fffe4edf18d77c10b32f09bcf8233 +======= + ## All angles assume radians. +>>>>>>> more changes result[0, 0] = cos(angle) result[0, 1] = -sin(angle) result[0, 2] = 0 @@ -1372,6 +1389,10 @@ proc toAngles*[T](a: GVec3[T]): GVec3[T] = ## pitch (x rotation) ## yaw (y rotation) ## roll (z rotation) - always 0 in vector case +<<<<<<< 6e2906d9898fffe4edf18d77c10b32f09bcf8233 +======= + ## All angles assume radians. +>>>>>>> more changes if a == gvec3[T](T(0), T(0), T(0)): return let @@ -1385,6 +1406,10 @@ proc toAngles*[T](origin, target: GVec3[T]): GVec3[T] = ## pitch (x rotation) ## yaw (y rotation) ## roll (z rotation) - always 0 in vector case +<<<<<<< 6e2906d9898fffe4edf18d77c10b32f09bcf8233 +======= + ## All angles assume radians. +>>>>>>> more changes toAngles(target - origin) proc toAngles*[T](m: GMat4[T]): GVec3[T] = @@ -1393,6 +1418,10 @@ proc toAngles*[T](m: GMat4[T]): GVec3[T] = ## yaw (y rotation) ## roll (z rotation) ## Assumes matrix has not been scaled. +<<<<<<< 6e2906d9898fffe4edf18d77c10b32f09bcf8233 +======= + ## All angles assume radians. +>>>>>>> more changes result.x = arcsin(m[2,1]) if result.x > PI/2: # Degenerate case over north pole. @@ -1407,6 +1436,10 @@ proc toAngles*[T](m: GMat4[T]): GVec3[T] = proc fromAngles*[T](a: GVec3[T]): GMat4[T] = ## Takes a vector containing Euler angles and returns a matrix. +<<<<<<< 6e2906d9898fffe4edf18d77c10b32f09bcf8233 +======= + ## All angles assume radians. +>>>>>>> more changes rotateY(a.y) * rotateX(a.x) * rotateZ(a.z) proc frustum*[T](left, right, bottom, top, near, far: T): GMat4[T] = @@ -1742,7 +1775,10 @@ proc rotate*[T](angle: T, axis: GVec3[T]): GMat4[T] = ## Return a rotation matrix with axis and angle. fromAxisAngle(axis, angle).mat4() +<<<<<<< 6e2906d9898fffe4edf18d77c10b32f09bcf8233 +======= +>>>>>>> more changes when defined(release): {.pop.} {.pop.} From 336ef5c7648db6c929fb10373db67cdbbd9e8508 Mon Sep 17 00:00:00 2001 From: treeform Date: Thu, 11 May 2023 22:20:22 -0700 Subject: [PATCH 10/11] fix merge junk --- src/vmath.nim | 29 ----------------------------- 1 file changed, 29 deletions(-) diff --git a/src/vmath.nim b/src/vmath.nim index 438c150..07f9029 100644 --- a/src/vmath.nim +++ b/src/vmath.nim @@ -1285,12 +1285,8 @@ proc translate*[T](v: GVec3[T]): GMat4[T] = ) proc rotate*[T](angle: T): GMat3[T] = -<<<<<<< 6e2906d9898fffe4edf18d77c10b32f09bcf8233 - ## Create a 2d rotation matrix by an angle. -======= ## Create a 2D rotation matrix by an angle. ## All angles assume radians. ->>>>>>> more changes let sin = sin(angle) cos = cos(angle) @@ -1308,10 +1304,7 @@ proc rotationOnly*[T](a: GMat4[T]): GMat4[T] {.inline.} = proc rotateX*[T](angle: T): GMat4[T] = ## Return a rotation matrix around X with angle. -<<<<<<< 6e2906d9898fffe4edf18d77c10b32f09bcf8233 -======= ## All angles assume radians. ->>>>>>> more changes result[0, 0] = 1 result[0, 1] = 0 result[0, 2] = 0 @@ -1334,10 +1327,7 @@ proc rotateX*[T](angle: T): GMat4[T] = proc rotateY*[T](angle: T): GMat4[T] = ## Return a rotation matrix around Y with angle. -<<<<<<< 6e2906d9898fffe4edf18d77c10b32f09bcf8233 -======= ## All angles assume radians. ->>>>>>> more changes result[0, 0] = cos(angle) result[0, 1] = 0 result[0, 2] = sin(angle) @@ -1360,10 +1350,7 @@ proc rotateY*[T](angle: T): GMat4[T] = proc rotateZ*[T](angle: T): GMat4[T] = ## Return a rotation matrix around Z with angle. -<<<<<<< 6e2906d9898fffe4edf18d77c10b32f09bcf8233 -======= ## All angles assume radians. ->>>>>>> more changes result[0, 0] = cos(angle) result[0, 1] = -sin(angle) result[0, 2] = 0 @@ -1389,10 +1376,7 @@ proc toAngles*[T](a: GVec3[T]): GVec3[T] = ## pitch (x rotation) ## yaw (y rotation) ## roll (z rotation) - always 0 in vector case -<<<<<<< 6e2906d9898fffe4edf18d77c10b32f09bcf8233 -======= ## All angles assume radians. ->>>>>>> more changes if a == gvec3[T](T(0), T(0), T(0)): return let @@ -1406,10 +1390,7 @@ proc toAngles*[T](origin, target: GVec3[T]): GVec3[T] = ## pitch (x rotation) ## yaw (y rotation) ## roll (z rotation) - always 0 in vector case -<<<<<<< 6e2906d9898fffe4edf18d77c10b32f09bcf8233 -======= ## All angles assume radians. ->>>>>>> more changes toAngles(target - origin) proc toAngles*[T](m: GMat4[T]): GVec3[T] = @@ -1418,10 +1399,7 @@ proc toAngles*[T](m: GMat4[T]): GVec3[T] = ## yaw (y rotation) ## roll (z rotation) ## Assumes matrix has not been scaled. -<<<<<<< 6e2906d9898fffe4edf18d77c10b32f09bcf8233 -======= ## All angles assume radians. ->>>>>>> more changes result.x = arcsin(m[2,1]) if result.x > PI/2: # Degenerate case over north pole. @@ -1436,10 +1414,7 @@ proc toAngles*[T](m: GMat4[T]): GVec3[T] = proc fromAngles*[T](a: GVec3[T]): GMat4[T] = ## Takes a vector containing Euler angles and returns a matrix. -<<<<<<< 6e2906d9898fffe4edf18d77c10b32f09bcf8233 -======= ## All angles assume radians. ->>>>>>> more changes rotateY(a.y) * rotateX(a.x) * rotateZ(a.z) proc frustum*[T](left, right, bottom, top, near, far: T): GMat4[T] = @@ -1775,10 +1750,6 @@ proc rotate*[T](angle: T, axis: GVec3[T]): GMat4[T] = ## Return a rotation matrix with axis and angle. fromAxisAngle(axis, angle).mat4() -<<<<<<< 6e2906d9898fffe4edf18d77c10b32f09bcf8233 - -======= ->>>>>>> more changes when defined(release): {.pop.} {.pop.} From 5e6ca01b16b45c84f3ff0fdec048f7cdb1038530 Mon Sep 17 00:00:00 2001 From: treeform Date: Thu, 11 May 2023 22:24:49 -0700 Subject: [PATCH 11/11] v2.0.0 --- vmath.nimble | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/vmath.nimble b/vmath.nimble index c414c6c..0198ad3 100644 --- a/vmath.nimble +++ b/vmath.nimble @@ -1,4 +1,4 @@ -version = "1.2.0" +version = "2.0.0" author = "Andre von Houck" description = "Your single stop for vector math routines for 2d and 3d graphics." license = "MIT"