123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839 |
- package raylib
- import "core:math"
- import "core:math/linalg"
- EPSILON :: 0.000001
- //----------------------------------------------------------------------------------
- // Module Functions Definition - Utils math
- //----------------------------------------------------------------------------------
- // Clamp float value
- @(require_results)
- Clamp :: proc "c" (value: f32, min, max: f32) -> f32 {
- return clamp(value, min, max)
- }
- // Calculate linear interpolation between two floats
- @(require_results)
- Lerp :: proc "c" (start, end: f32, amount: f32) -> f32 {
- return start*(1-amount) + end*amount
- }
- // Normalize input value within input range
- @(require_results)
- Normalize :: proc "c" (value: f32, start, end: f32) -> f32 {
- return (value - start) / (end - start)
- }
- // Remap input value within input range to output range
- @(require_results)
- Remap :: proc "c" (value: f32, inputStart, inputEnd: f32, outputStart, outputEnd: f32) -> f32 {
- return (value - inputStart)/(inputEnd - inputStart)*(outputEnd - outputStart) + outputStart
- }
- // Wrap input value from min to max
- @(require_results)
- Wrap :: proc "c" (value: f32, min, max: f32) -> f32 {
- return value - (max - min)*math.floor((value - min)/(max - min))
- }
- // Check whether two given floats are almost equal
- @(require_results)
- FloatEquals :: proc "c" (x, y: f32) -> bool {
- return abs(x - y) <= EPSILON*fmaxf(1.0, fmaxf(abs(x), abs(y)))
- }
- //----------------------------------------------------------------------------------
- // Module Functions Definition - Vector2 math
- //----------------------------------------------------------------------------------
- // Vector with components value 0.0
- @(require_results, deprecated="Prefer Vector2(0)")
- Vector2Zero :: proc "c" () -> Vector2 {
- return Vector2(0)
- }
- // Vector with components value 1.0
- @(require_results, deprecated="Prefer Vector2(1)")
- Vector2One :: proc "c" () -> Vector2 {
- return Vector2(1)
- }
- // Add two vectors (v1 + v2)
- @(require_results, deprecated="Prefer v1 + v2")
- Vector2Add :: proc "c" (v1, v2: Vector2) -> Vector2 {
- return v1 + v2
- }
- // Add vector and float value
- @(require_results, deprecated="Prefer v + value")
- Vector2AddValue :: proc "c" (v: Vector2, value: f32) -> Vector2 {
- return v + value
- }
- // Subtract two vectors (v1 - v2)
- @(require_results, deprecated="Prefer a - b")
- Vector2Subtract :: proc "c" (a, b: Vector2) -> Vector2 {
- return a - b
- }
- // Subtract vector by float value
- @(require_results, deprecated="Prefer v + value")
- Vector2SubtractValue :: proc "c" (v: Vector2, value: f32) -> Vector2 {
- return v - value
- }
- // Calculate vector length
- @(require_results)
- Vector2Length :: proc "c" (v: Vector2) -> f32 {
- return linalg.length(v)
- }
- // Calculate vector square length
- @(require_results)
- Vector2LengthSqr :: proc "c" (v: Vector2) -> f32 {
- return linalg.length2(v)
- }
- // Calculate two vectors dot product
- @(require_results)
- Vector2DotProduct :: proc "c" (v1, v2: Vector2) -> f32 {
- return linalg.dot(v1, v2)
- }
- // Calculate distance between two vectors
- @(require_results)
- Vector2Distance :: proc "c" (v1, v2: Vector2) -> f32 {
- return linalg.distance(v1, v2)
- }
- // Calculate square distance between two vectors
- @(require_results)
- Vector2DistanceSqrt :: proc "c" (v1, v2: Vector2) -> f32 {
- return linalg.length2(v2-v1)
- }
- // Calculate angle between two vectors
- // NOTE: Angle is calculated from origin point (0, 0)
- @(require_results)
- Vector2Angle :: proc "c" (v1, v2: Vector2) -> f32 {
- return linalg.angle_between(v1, v2)
- }
- // Calculate angle defined by a two vectors line
- // NOTE: Parameters need to be normalized
- // Current implementation should be aligned with glm::angle
- @(require_results)
- Vector2LineAngle :: proc "c" (start, end: Vector2) -> f32 {
- // TODO(10/9/2023): Currently angles move clockwise, determine if this is wanted behavior
- return -math.atan2(end.y - start.y, end.x - start.x)
- }
- // Scale vector (multiply by value)
- @(require_results, deprecated="Prefer v * scale")
- Vector2Scale :: proc "c" (v: Vector2, scale: f32) -> Vector2 {
- return v * scale
- }
- // Multiply vector by vector
- @(require_results, deprecated="Prefer v1 * v2")
- Vector2Multiply :: proc "c" (v1, v2: Vector2) -> Vector2 {
- return v1 * v2
- }
- // Negate vector
- @(require_results, deprecated="Prefer -v")
- Vector2Negate :: proc "c" (v: Vector2) -> Vector2 {
- return -v
- }
- // Divide vector by vector
- @(require_results, deprecated="Prefer v1 / v2")
- Vector2Divide :: proc "c" (v1, v2: Vector2) -> Vector2 {
- return v1 / v2
- }
- // Normalize provided vector
- @(require_results)
- Vector2Normalize :: proc "c" (v: Vector2) -> Vector2 {
- return linalg.normalize0(v)
- }
- // Transforms a Vector2 by a given Matrix
- @(require_results)
- Vector2Transform :: proc "c" (v: Vector2, m: Matrix) -> Vector2 {
- v4 := Vector4{v.x, v.y, 0, 1}
- return (m * v4).xy
- }
- // Calculate linear interpolation between two vectors
- @(require_results, deprecated="Prefer = linalg.lerp(v1, v2, amount)")
- Vector2Lerp :: proc "c" (v1, v2: Vector2, amount: f32) -> Vector2 {
- return linalg.lerp(v1, v2, Vector2(amount))
- }
- // Calculate reflected vector to normal
- @(require_results, deprecated="Prefer = linalg.reflect(v, normal)")
- Vector2Reflect :: proc "c" (v, normal: Vector2) -> Vector2 {
- return linalg.reflect(v, normal)
- }
- // Rotate vector by angle
- @(require_results)
- Vector2Rotate :: proc "c" (v: Vector2, angle: f32) -> Vector2 {
- c, s := math.cos(angle), math.sin(angle)
- return Vector2{
- v.x*c - v.y*s,
- v.x*s + v.y*c,
- }
- }
- // Move Vector towards target
- @(require_results)
- Vector2MoveTowards :: proc "c" (v, target: Vector2, maxDistance: f32) -> Vector2 {
- dv := target - v
- value := linalg.dot(dv, dv)
- if value == 0 || (maxDistance >= 0 && value <= maxDistance*maxDistance) {
- return target
- }
- dist := math.sqrt(value)
- return v + dv/dist*maxDistance
- }
- // Invert the given vector
- @(require_results, deprecated="Prefer 1.0/v")
- Vector2Invert :: proc "c" (v: Vector2) -> Vector2 {
- return 1.0/v
- }
- // Clamp the components of the vector between
- // min and max values specified by the given vectors
- @(require_results)
- Vector2Clamp :: proc "c" (v: Vector2, min, max: Vector2) -> Vector2 {
- return Vector2{
- clamp(v.x, min.x, max.x),
- clamp(v.y, min.y, max.y),
- }
- }
- // Clamp the magnitude of the vector between two min and max values
- @(require_results)
- Vector2ClampValue :: proc "c" (v: Vector2, min, max: f32) -> Vector2 {
- result := v
- length := linalg.dot(v, v)
- if length > 0 {
- length = math.sqrt(length)
- scale := f32(1)
- if length < min {
- scale = min/length
- } else if length > max {
- scale = max/length
- }
- result = v*scale
- }
- return result
- }
- @(require_results)
- Vector2Equals :: proc "c" (p, q: Vector2) -> bool {
- return FloatEquals(p.x, q.x) &&
- FloatEquals(p.y, q.y)
- }
- //----------------------------------------------------------------------------------
- // Module Functions Definition - Vector3 math
- //----------------------------------------------------------------------------------
- // Vector with components value 0.0
- @(require_results, deprecated="Prefer Vector3(0)")
- Vector3Zero :: proc "c" () -> Vector3 {
- return Vector3(0)
- }
- // Vector with components value 1.0
- @(require_results, deprecated="Prefer Vector3(1)")
- Vector3One :: proc "c" () -> Vector3 {
- return Vector3(1)
- }
- // Add two vectors (v1 + v2)
- @(require_results, deprecated="Prefer v1 + v2")
- Vector3Add :: proc "c" (v1, v2: Vector3) -> Vector3 {
- return v1 + v2
- }
- // Add vector and float value
- @(require_results, deprecated="Prefer v + value")
- Vector3AddValue :: proc "c" (v: Vector3, value: f32) -> Vector3 {
- return v + value
- }
- // Subtract two vectors (v1 - v2)
- @(require_results, deprecated="Prefer a - b")
- Vector3Subtract :: proc "c" (a, b: Vector3) -> Vector3 {
- return a - b
- }
- // Subtract vector by float value
- @(require_results, deprecated="Prefer v + value")
- Vector3SubtractValue :: proc "c" (v: Vector3, value: f32) -> Vector3 {
- return v - value
- }
- // Calculate vector length
- @(require_results)
- Vector3Length :: proc "c" (v: Vector3) -> f32 {
- return linalg.length(v)
- }
- // Calculate vector square length
- @(require_results)
- Vector3LengthSqr :: proc "c" (v: Vector3) -> f32 {
- return linalg.length2(v)
- }
- // Calculate two vectors dot product
- @(require_results)
- Vector3DotProduct :: proc "c" (v1, v2: Vector3) -> f32 {
- return linalg.dot(v1, v2)
- }
- // Calculate two vectors dot product
- @(require_results)
- Vector3CrossProduct :: proc "c" (v1, v2: Vector3) -> Vector3 {
- return linalg.cross(v1, v2)
- }
- // Calculate distance between two vectors
- @(require_results)
- Vector3Distance :: proc "c" (v1, v2: Vector3) -> f32 {
- return linalg.distance(v1, v2)
- }
- // Calculate square distance between two vectors
- @(require_results)
- Vector3DistanceSqrt :: proc "c" (v1, v2: Vector3) -> f32 {
- return linalg.length2(v2-v1)
- }
- // Calculate angle between two vectors
- // NOTE: Angle is calculated from origin point (0, 0)
- @(require_results)
- Vector3Angle :: proc "c" (v1, v2: Vector3) -> f32 {
- return linalg.angle_between(v1, v2)
- }
- // Calculate angle defined by a two vectors line
- // NOTE: Parameters need to be normalized
- // Current implementation should be aligned with glm::angle
- @(require_results)
- Vector3LineAngle :: proc "c" (start, end: Vector3) -> f32 {
- // TODO(10/9/2023): Currently angles move clockwise, determine if this is wanted behavior
- return -math.atan2(end.y - start.y, end.x - start.x)
- }
- // Scale vector (multiply by value)
- @(require_results, deprecated="Prefer v * scale")
- Vector3Scale :: proc "c" (v: Vector3, scale: f32) -> Vector3 {
- return v * scale
- }
- // Multiply vector by vector
- @(require_results, deprecated="Prefer v1 * v2")
- Vector3Multiply :: proc "c" (v1, v2: Vector3) -> Vector3 {
- return v1 * v2
- }
- // Negate vector
- @(require_results, deprecated="Prefer -v")
- Vector3Negate :: proc "c" (v: Vector3) -> Vector3 {
- return -v
- }
- // Divide vector by vector
- @(require_results, deprecated="Prefer v1 / v2")
- Vector3Divide :: proc "c" (v1, v2: Vector3) -> Vector3 {
- return v1 / v2
- }
- // Normalize provided vector
- @(require_results)
- Vector3Normalize :: proc "c" (v: Vector3) -> Vector3 {
- return linalg.normalize0(v)
- }
- // Calculate the projection of the vector v1 on to v2
- @(require_results)
- Vector3Project :: proc "c" (v1, v2: Vector3) -> Vector3 {
- return linalg.projection(v1, v2)
- }
- // Calculate the rejection of the vector v1 on to v2
- @(require_results)
- Vector3Reject :: proc "c" (v1, v2: Vector3) -> Vector3 {
- mag := linalg.dot(v1, v2)/linalg.dot(v2, v2)
- return v1 - v2*mag
- }
- // Orthonormalize provided vectors
- // Makes vectors normalized and orthogonal to each other
- // Gram-Schmidt function implementation
- Vector3OrthoNormalize :: proc "c" (v1, v2: ^Vector3) {
- v1^ = linalg.normalize0(v1^)
- v3 := linalg.normalize0(linalg.cross(v1^, v2^))
- v2^ = linalg.cross(v3, v1^)
- }
- // Transform a vector by quaternion rotation
- @(require_results)
- Vector3RotateByQuaternion :: proc "c" (v: Vector3, q: Quaternion) -> Vector3 {
- return linalg.mul(q, v)
- }
- // Rotates a vector around an axis
- @(require_results)
- Vector3RotateByAxisAngle :: proc "c" (v: Vector3, axis: Vector3, angle: f32) -> Vector3 {
- axis, angle := axis, angle
- axis = linalg.normalize0(axis)
- angle *= 0.5
- a := math.sin(angle)
- b := axis.x*a
- c := axis.y*a
- d := axis.z*a
- a = math.cos(angle)
- w := Vector3{b, c, d}
- wv := linalg.cross(w, v)
- wwv := linalg.cross(w, wv)
- a *= 2
- wv *= a
- wwv *= 2
- return v + wv + wwv
- }
- // Transforms a Vector3 by a given Matrix
- @(require_results)
- Vector3Transform :: proc "c" (v: Vector3, m: Matrix) -> Vector3 {
- v4 := Vector4{v.x, v.y, v.z, 1}
- return (m * v4).xyz
- }
- // Calculate linear interpolation between two vectors
- @(require_results, deprecated="Prefer = linalg.lerp(v1, v2, amount)")
- Vector3Lerp :: proc "c" (v1, v2: Vector3, amount: f32) -> Vector3 {
- return linalg.lerp(v1, v2, Vector3(amount))
- }
- // Calculate reflected vector to normal
- @(require_results, deprecated="Prefer = linalg.reflect(v, normal)")
- Vector3Reflect :: proc "c" (v, normal: Vector3) -> Vector3 {
- return linalg.reflect(v, normal)
- }
- // Compute the direction of a refracted ray
- // v: normalized direction of the incoming ray
- // n: normalized normal vector of the interface of two optical media
- // r: ratio of the refractive index of the medium from where the ray comes
- // to the refractive index of the medium on the other side of the surface
- @(require_results, deprecated="Prefer = linalg.refract(v, n, r)")
- Vector3Refract :: proc "c" (v, n: Vector3, r: f32) -> Vector3 {
- return linalg.refract(v, n, r)
- }
- // Move Vector towards target
- @(require_results)
- Vector3MoveTowards :: proc "c" (v, target: Vector3, maxDistance: f32) -> Vector3 {
- dv := target - v
- value := linalg.dot(dv, dv)
- if value == 0 || (maxDistance >= 0 && value <= maxDistance*maxDistance) {
- return target
- }
- dist := math.sqrt(value)
- return v + dv/dist*maxDistance
- }
- // Invert the given vector
- @(require_results, deprecated="Prefer 1.0/v")
- Vector3Invert :: proc "c" (v: Vector3) -> Vector3 {
- return 1.0/v
- }
- // Clamp the components of the vector between
- // min and max values specified by the given vectors
- @(require_results)
- Vector3Clamp :: proc "c" (v: Vector3, min, max: Vector3) -> Vector3 {
- return Vector3{
- clamp(v.x, min.x, max.x),
- clamp(v.y, min.y, max.y),
- clamp(v.z, min.z, max.z),
- }
- }
- // Clamp the magnitude of the vector between two min and max values
- @(require_results)
- Vector3ClampValue :: proc "c" (v: Vector3, min, max: f32) -> Vector3 {
- result := v
- length := linalg.dot(v, v)
- if length > 0 {
- length = math.sqrt(length)
- scale := f32(1)
- if length < min {
- scale = min/length
- } else if length > max {
- scale = max/length
- }
- result = v*scale
- }
- return result
- }
- @(require_results)
- Vector3Equals :: proc "c" (p, q: Vector3) -> bool {
- return FloatEquals(p.x, q.x) &&
- FloatEquals(p.y, q.y) &&
- FloatEquals(p.z, q.z)
- }
- @(require_results)
- Vector3Min :: proc "c" (v1, v2: Vector3) -> Vector3 {
- return linalg.min(v1, v2)
- }
- @(require_results)
- Vector3Max :: proc "c" (v1, v2: Vector3) -> Vector3 {
- return linalg.max(v1, v2)
- }
- // Compute barycenter coordinates (u, v, w) for point p with respect to triangle (a, b, c)
- // NOTE: Assumes P is on the plane of the triangle
- @(require_results)
- Vector3Barycenter :: proc "c" (p: Vector3, a, b, c: Vector3) -> (result: Vector3) {
- v0 := b - a
- v1 := c - a
- v2 := p - a
- d00 := linalg.dot(v0, v0)
- d01 := linalg.dot(v0, v1)
- d11 := linalg.dot(v1, v1)
- d20 := linalg.dot(v2, v0)
- d21 := linalg.dot(v2, v1)
- denom := d00*d11 - d01*d01
- result.y = (d11*d20 - d01*d21)/denom
- result.z = (d00*d21 - d01*d20)/denom
- result.x = 1 - (result.z + result.y)
- return result
- }
- // Projects a Vector3 from screen space into object space
- @(require_results)
- Vector3Unproject :: proc "c" (source: Vector3, projection: Matrix, view: Matrix) -> Vector3 {
- matViewProj := view * projection
- matViewProjInv := linalg.inverse(matViewProj)
- quat: Quaternion
- quat.x = source.x
- quat.y = source.y
- quat.z = source.z
- quat.w = 1
- qtransformed := QuaternionTransform(quat, matViewProjInv)
- return Vector3{qtransformed.x/qtransformed.w, qtransformed.y/qtransformed.w, qtransformed.z/qtransformed.w}
- }
- //----------------------------------------------------------------------------------
- // Module Functions Definition - Matrix math
- //----------------------------------------------------------------------------------
- // Compute matrix determinant
- @(require_results)
- MatrixDeterminant :: proc "c" (mat: Matrix) -> f32 {
- return linalg.determinant(mat)
- }
- // Get the trace of the matrix (sum of the values along the diagonal)
- @(require_results)
- MatrixTrace :: proc "c" (mat: Matrix) -> f32 {
- return linalg.trace(mat)
- }
- // Transposes provided matrix
- @(require_results)
- MatrixTranspose :: proc "c" (mat: Matrix) -> Matrix {
- return linalg.transpose(mat)
- }
- // Invert provided matrix
- @(require_results)
- MatrixInvert :: proc "c" (mat: Matrix) -> Matrix {
- return linalg.inverse(mat)
- }
- // Get identity matrix
- @(require_results, deprecated="Prefer Matrix(1)")
- MatrixIdentity :: proc "c" () -> Matrix {
- return Matrix(1)
- }
- // Add two matrices
- @(require_results, deprecated="Prefer left + right")
- MatrixAdd :: proc "c" (left, right: Matrix) -> Matrix {
- return left + right
- }
- // Subtract two matrices (left - right)
- @(require_results, deprecated="Prefer left - right")
- MatrixSubtract :: proc "c" (left, right: Matrix) -> Matrix {
- return left - right
- }
- // Get two matrix multiplication
- // NOTE: When multiplying matrices... the order matters!
- @(require_results, deprecated="Prefer left * right")
- MatrixMultiply :: proc "c" (left, right: Matrix) -> Matrix {
- return left * right
- }
- // Get translation matrix
- @(require_results)
- MatrixTranslate :: proc "c" (x, y, z: f32) -> Matrix {
- return {
- 1, 0, 0, x,
- 0, 1, 0, y,
- 0, 0, 1, z,
- 0, 0, 0, 1,
- }
- }
- // Create rotation matrix from axis and angle
- // NOTE: Angle should be provided in radians
- @(require_results)
- MatrixRotate :: proc "c" (axis: Vector3, angle: f32) -> Matrix {
- return auto_cast linalg.matrix4_rotate(angle, axis)
- }
- // Get x-rotation matrix
- // NOTE: Angle must be provided in radians
- @(require_results)
- MatrixRotateX :: proc "c" (angle: f32) -> Matrix {
- return auto_cast linalg.matrix4_rotate(angle, Vector3{1, 0, 0})
- }
- // Get y-rotation matrix
- // NOTE: Angle must be provided in radians
- @(require_results)
- MatrixRotateY :: proc "c" (angle: f32) -> Matrix {
- return auto_cast linalg.matrix4_rotate(angle, Vector3{0, 1, 0})
- }
- // Get z-rotation matrix
- // NOTE: Angle must be provided in radians
- @(require_results)
- MatrixRotateZ :: proc "c" (angle: f32) -> Matrix {
- return auto_cast linalg.matrix4_rotate(angle, Vector3{0, 0, 1})
- }
- // Get xyz-rotation matrix
- // NOTE: Angle must be provided in radians
- @(require_results)
- MatrixRotateXYZ :: proc "c" (angle: Vector3) -> Matrix {
- return auto_cast linalg.matrix4_from_euler_angles_xyz(angle.x, angle.y, angle.z)
- }
- // Get zyx-rotation matrix
- // NOTE: Angle must be provided in radians
- @(require_results)
- MatrixRotateZYX :: proc "c" (angle: Vector3) -> Matrix {
- return auto_cast linalg.matrix4_from_euler_angles_zyx(angle.x, angle.y, angle.z)
- }
- // Get scaling matrix
- @(require_results)
- MatrixScale :: proc "c" (x, y, z: f32) -> Matrix {
- return auto_cast linalg.matrix4_scale(Vector3{x, y, z})
- }
- // Get orthographic projection matrix
- @(require_results)
- MatrixOrtho :: proc "c" (left, right, bottom, top, near, far: f32) -> Matrix {
- return auto_cast linalg.matrix_ortho3d(left, right, bottom, top, near, far)
- }
- // Get perspective projection matrix
- // NOTE: Fovy angle must be provided in radians
- @(require_results)
- MatrixPerspective :: proc "c" (fovY, aspect, nearPlane, farPlane: f32) -> Matrix {
- return auto_cast linalg.matrix4_perspective(fovY, aspect, nearPlane, farPlane)
- }
- // Get camera look-at matrix (view matrix)
- @(require_results)
- MatrixLookAt :: proc "c" (eye, target, up: Vector3) -> Matrix {
- return auto_cast linalg.matrix4_look_at(eye, target, up)
- }
- // Get float array of matrix data
- @(require_results)
- MatrixToFloatV :: proc "c" (mat: Matrix) -> [16]f32 {
- return transmute([16]f32)linalg.transpose(mat)
- }
- //----------------------------------------------------------------------------------
- // Module Functions Definition - Quaternion math
- //----------------------------------------------------------------------------------
- // Add two quaternions
- @(require_results, deprecated="Prefer q1 + q2")
- QuaternionAdd :: proc "c" (q1, q2: Quaternion) -> Quaternion {
- return q1 + q2
- }
- // Add quaternion and float value
- @(require_results)
- QuaternionAddValue :: proc "c" (q: Quaternion, add: f32) -> Quaternion {
- return q + Quaternion(add)
- }
- // Subtract two quaternions
- @(require_results, deprecated="Prefer q1 - q2")
- QuaternionSubtract :: proc "c" (q1, q2: Quaternion) -> Quaternion {
- return q1 - q2
- }
- // Subtract quaternion and float value
- @(require_results)
- QuaternionSubtractValue :: proc "c" (q: Quaternion, sub: f32) -> Quaternion {
- return q - Quaternion(sub)
- }
- // Get identity quaternion
- @(require_results, deprecated="Prefer Quaternion(1)")
- QuaternionIdentity :: proc "c" () -> Quaternion {
- return 1
- }
- // Computes the length of a quaternion
- @(require_results, deprecated="Prefer abs(q)")
- QuaternionLength :: proc "c" (q: Quaternion) -> f32 {
- return abs(q)
- }
- // Normalize provided quaternion
- @(require_results)
- QuaternionNormalize :: proc "c" (q: Quaternion) -> Quaternion {
- return linalg.normalize0(q)
- }
- // Invert provided quaternion
- @(require_results, deprecated="Prefer 1/q")
- QuaternionInvert :: proc "c" (q: Quaternion) -> Quaternion {
- return 1/q
- }
- // Calculate two quaternion multiplication
- @(require_results, deprecated="Prefer q1 * q2")
- QuaternionMultiply :: proc "c" (q1, q2: Quaternion) -> Quaternion {
- return q1 * q2
- }
- // Scale quaternion by float value
- @(require_results)
- QuaternionScale :: proc "c" (q: Quaternion, mul: f32) -> Quaternion {
- return q * Quaternion(mul)
- }
- // Divide two quaternions
- @(require_results, deprecated="Prefer q1 / q2")
- QuaternionDivide :: proc "c" (q1, q2: Quaternion) -> Quaternion {
- return q1 / q2
- }
- // Calculate linear interpolation between two quaternions
- @(require_results)
- QuaternionLerp :: proc "c" (q1, q2: Quaternion, amount: f32) -> (q3: Quaternion) {
- q3.x = q1.x + (q2.x-q1.x)*amount
- q3.y = q1.y + (q2.y-q1.y)*amount
- q3.z = q1.z + (q2.z-q1.z)*amount
- q3.w = q1.w + (q2.w-q1.w)*amount
- return
- }
- // Calculate slerp-optimized interpolation between two quaternions
- @(require_results)
- QuaternionNlerp :: proc "c" (q1, q2: Quaternion, amount: f32) -> Quaternion {
- return linalg.quaternion_nlerp(q1, q2, amount)
- }
- // Calculates spherical linear interpolation between two quaternions
- @(require_results)
- QuaternionSlerp :: proc "c" (q1, q2: Quaternion, amount: f32) -> Quaternion {
- return linalg.quaternion_slerp(q1, q2, amount)
- }
- // Calculate quaternion based on the rotation from one vector to another
- @(require_results)
- QuaternionFromVector3ToVector3 :: proc "c" (from, to: Vector3) -> Quaternion {
- return linalg.quaternion_between_two_vector3(from, to)
- }
- // Get a quaternion for a given rotation matrix
- @(require_results)
- QuaternionFromMatrix :: proc "c" (mat: Matrix) -> Quaternion {
- return linalg.quaternion_from_matrix4(linalg.Matrix4f32(mat))
- }
- // Get a matrix for a given quaternion
- @(require_results)
- QuaternionToMatrix :: proc "c" (q: Quaternion) -> Matrix {
- return auto_cast linalg.matrix4_from_quaternion(q)
- }
- // Get rotation quaternion for an angle and axis NOTE: Angle must be provided in radians
- @(require_results)
- QuaternionFromAxisAngle :: proc "c" (axis: Vector3, angle: f32) -> Quaternion {
- return linalg.quaternion_angle_axis(angle, axis)
- }
- // Get the rotation angle and axis for a given quaternion
- @(require_results)
- QuaternionToAxisAngle :: proc "c" (q: Quaternion) -> (outAxis: Vector3, outAngle: f32) {
- outAngle, outAxis = linalg.angle_axis_from_quaternion(q)
- return
- }
- // Get the quaternion equivalent to Euler angles NOTE: Rotation order is ZYX
- @(require_results)
- QuaternionFromEuler :: proc "c" (pitch, yaw, roll: f32) -> Quaternion {
- return linalg.quaternion_from_pitch_yaw_roll(pitch, yaw, roll)
- }
- // Get the Euler angles equivalent to quaternion (roll, pitch, yaw) NOTE: Angles are returned in a Vector3 struct in radians
- @(require_results)
- QuaternionToEuler :: proc "c" (q: Quaternion) -> Vector3 {
- result: Vector3
- // Roll (x-axis rotation)
- x0 := 2.0*(q.w*q.x + q.y*q.z)
- x1 := 1.0 - 2.0*(q.x*q.x + q.y*q.y)
- result.x = math.atan2(x0, x1)
- // Pitch (y-axis rotation)
- y0 := 2.0*(q.w*q.y - q.z*q.x)
- y0 = 1.0 if y0 > 1.0 else y0
- y0 = -1.0 if y0 < -1.0 else y0
- result.y = math.asin(y0)
- // Yaw (z-axis rotation)
- z0 := 2.0*(q.w*q.z + q.x*q.y)
- z1 := 1.0 - 2.0*(q.y*q.y + q.z*q.z)
- result.z = math.atan2(z0, z1)
- return result
- }
- // Transform a quaternion given a transformation matrix
- @(require_results)
- QuaternionTransform :: proc "c" (q: Quaternion, mat: Matrix) -> Quaternion {
- v := mat * transmute(Vector4)q
- return transmute(Quaternion)v
- }
- // Check whether two given quaternions are almost equal
- @(require_results)
- QuaternionEquals :: proc "c" (p, q: Quaternion) -> bool {
- return FloatEquals(p.x, q.x) &&
- FloatEquals(p.y, q.y) &&
- FloatEquals(p.z, q.z) &&
- FloatEquals(p.w, q.w)
- }
- @(private, require_results)
- fmaxf :: proc "contextless" (x, y: f32) -> f32 {
- if math.is_nan(x) {
- return y
- }
- if math.is_nan(y) {
- return x
- }
- if math.sign_bit(x) != math.sign_bit(y) {
- return y if math.sign_bit(x) else x
- }
- return y if x < y else x
- }
|