├── .gitignore ├── .travis.yml ├── tests ├── elm-package.json └── Tests.elm ├── elm-package.json ├── CONTRIBUTING.md ├── README.md ├── LICENSE └── src ├── Math ├── Vector2.elm ├── Vector4.elm ├── Vector3.elm └── Matrix4.elm └── Native ├── Math ├── Vector2.js └── Vector4.js └── MJS.js /.gitignore: -------------------------------------------------------------------------------- 1 | elm-stuff -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: node_js 2 | node_js: 3 | - "5" 4 | install: 5 | - npm install -g elm@0.18.0 elm-test@0.18.12 6 | - elm-package install -y 7 | - pushd tests && elm-package install -y && popd 8 | script: 9 | - elm-test 10 | -------------------------------------------------------------------------------- /tests/elm-package.json: -------------------------------------------------------------------------------- 1 | { 2 | "version": "1.1.0", 3 | "summary": "Linear Algebra Test Suites", 4 | "repository": "https://github.com/elm-community/linear-algebra.git", 5 | "license": "BSD3", 6 | "source-directories": [ 7 | "../src", 8 | "." 9 | ], 10 | "exposed-modules": [], 11 | "native-modules": true, 12 | "dependencies": { 13 | "elm-lang/core": "5.0.0 <= v < 6.0.0", 14 | "elm-community/elm-test": "4.0.0 <= v < 5.0.0" 15 | }, 16 | "elm-version": "0.18.0 <= v < 0.19.0" 17 | } -------------------------------------------------------------------------------- /elm-package.json: -------------------------------------------------------------------------------- 1 | { 2 | "version": "3.1.1", 3 | "summary": "A linear algebra library for fast vector and matrix math", 4 | "repository": "https://github.com/elm-community/linear-algebra.git", 5 | "license": "BSD3", 6 | "source-directories": [ 7 | "src" 8 | ], 9 | "exposed-modules": [ 10 | "Math.Vector2", 11 | "Math.Vector3", 12 | "Math.Vector4", 13 | "Math.Matrix4" 14 | ], 15 | "native-modules": true, 16 | "dependencies": { 17 | "elm-lang/core": "5.0.0 <= v < 6.0.0" 18 | }, 19 | "elm-version": "0.18.0 <= v < 0.19.0" 20 | } 21 | -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | # Contributing to elm-community/linear-algebra 2 | 3 | This repository is kept for maintenance and does not accept most feature requests. In particular, 4 | [#5](https://github.com/elm-community/elm-linear-algebra/issues/5) requires that all 5 | changes be PATCH-level, meaning that the API cannot be modified. 6 | 7 | Any contribution should: 8 | * Compile using `elm make` 9 | * Be recognized as a PATCH change using `elm package diff` 10 | * Not introduce mutable variables 11 | * Justify why the change is needed and why it won't break anything already here 12 | 13 | Documentation improvements are welcome. 14 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | DEPRECATED: Moved to [elm-explorations/linear-algebra](https://package.elm-lang.org/packages/elm-explorations/linear-algebra/latest) 2 | 3 | # Fast Linear Algebra for Elm 4 | 5 | A library for fast vector and matrix math. See the full docs [here][docs]. 6 | 7 | [docs]: http://package.elm-lang.org/packages/elm-community/linear-algebra/latest/ 8 | 9 | This is needed for 3D rendering with [WebGL in Elm][webgl], but is useful for 10 | anything where fast linear algebra is needed. 11 | 12 | [webgl]: https://github.com/elm-community/elm-webgl 13 | 14 | It is based on [the MJS library](https://code.google.com/p/webgl-mjs/) for JavaScript. 15 | 16 | 17 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2014, John P Mayer, Jr 2 | All rights reserved. 3 | 4 | Redistribution and use in source and binary forms, with or without 5 | modification, are permitted provided that the following conditions are met: 6 | 7 | * Redistributions of source code must retain the above copyright notice, this 8 | list of conditions and the following disclaimer. 9 | 10 | * Redistributions in binary form must reproduce the above copyright notice, 11 | this list of conditions and the following disclaimer in the documentation 12 | and/or other materials provided with the distribution. 13 | 14 | * Neither the name of the {organization} nor the names of its 15 | contributors may be used to endorse or promote products derived from 16 | this software without specific prior written permission. 17 | 18 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 19 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 20 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 21 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 22 | FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 23 | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 24 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 25 | CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 26 | OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 27 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -------------------------------------------------------------------------------- /src/Math/Vector2.elm: -------------------------------------------------------------------------------- 1 | module Math.Vector2 2 | exposing 3 | ( Vec2 4 | , vec2 5 | , getX 6 | , getY 7 | , setX 8 | , setY 9 | , add 10 | , sub 11 | , negate 12 | , scale 13 | , dot 14 | , normalize 15 | , direction 16 | , length 17 | , lengthSquared 18 | , distance 19 | , distanceSquared 20 | , toTuple 21 | , fromTuple 22 | , toRecord 23 | , fromRecord 24 | ) 25 | 26 | {-| A high performance linear algebra library using native JS arrays. Geared 27 | towards 3D graphics and use with `Graphics.WebGL`. All vectors are immutable. 28 | 29 | # Create 30 | @docs Vec2, vec2 31 | 32 | # Get and Set 33 | The set functions create a new copy of the vector, updating a single field. 34 | 35 | @docs getX, getY, setX, setY 36 | 37 | # Operations 38 | @docs add, sub, negate, scale, dot, normalize, direction, 39 | length, lengthSquared, distance, distanceSquared 40 | 41 | # Conversions 42 | @docs toTuple, fromTuple, toRecord, fromRecord 43 | -} 44 | 45 | import Native.Math.Vector2 46 | 47 | 48 | {-| Two dimensional vector type 49 | -} 50 | type Vec2 51 | = Vec2 52 | 53 | 54 | {-| Creates a new 2-element vector with the given values. 55 | -} 56 | vec2 : Float -> Float -> Vec2 57 | vec2 = 58 | Native.Math.Vector2.vec2 59 | 60 | 61 | {-| Extract the x component of a vector. 62 | -} 63 | getX : Vec2 -> Float 64 | getX = 65 | Native.Math.Vector2.getX 66 | 67 | 68 | {-| Extract the y component of a vector. 69 | -} 70 | getY : Vec2 -> Float 71 | getY = 72 | Native.Math.Vector2.getY 73 | 74 | 75 | {-| Update the x component of a vector, returning a new vector. 76 | -} 77 | setX : Float -> Vec2 -> Vec2 78 | setX = 79 | Native.Math.Vector2.setX 80 | 81 | 82 | {-| Update the y component of a vector, returning a new vector. 83 | -} 84 | setY : Float -> Vec2 -> Vec2 85 | setY = 86 | Native.Math.Vector2.setY 87 | 88 | 89 | {-| Convert a vector to a tuple. 90 | -} 91 | toTuple : Vec2 -> ( Float, Float ) 92 | toTuple = 93 | Native.Math.Vector2.toTuple 94 | 95 | 96 | {-| Convert a vector to a record. 97 | -} 98 | toRecord : Vec2 -> { x : Float, y : Float } 99 | toRecord = 100 | Native.Math.Vector2.toRecord 101 | 102 | 103 | {-| Convert a tuple to a vector. 104 | -} 105 | fromTuple : ( Float, Float ) -> Vec2 106 | fromTuple = 107 | Native.Math.Vector2.fromTuple 108 | 109 | 110 | {-| Convert a record to a vector. 111 | -} 112 | fromRecord : { x : Float, y : Float } -> Vec2 113 | fromRecord = 114 | Native.Math.Vector2.fromRecord 115 | 116 | 117 | {-| Vector addition: a + b 118 | -} 119 | add : Vec2 -> Vec2 -> Vec2 120 | add = 121 | Native.Math.Vector2.add 122 | 123 | 124 | {-| Vector subtraction: a - b 125 | -} 126 | sub : Vec2 -> Vec2 -> Vec2 127 | sub = 128 | Native.Math.Vector2.sub 129 | 130 | 131 | {-| Vector negation: -a 132 | -} 133 | negate : Vec2 -> Vec2 134 | negate = 135 | Native.Math.Vector2.neg 136 | 137 | 138 | {-| The normalized direction from b to a: (a - b) / |a - b| 139 | -} 140 | direction : Vec2 -> Vec2 -> Vec2 141 | direction = 142 | Native.Math.Vector2.direction 143 | 144 | 145 | {-| The length of the given vector: |a| 146 | -} 147 | length : Vec2 -> Float 148 | length = 149 | Native.Math.Vector2.length 150 | 151 | 152 | {-| The square of the length of the given vector: |a| * |a| 153 | -} 154 | lengthSquared : Vec2 -> Float 155 | lengthSquared = 156 | Native.Math.Vector2.lengthSquared 157 | 158 | 159 | {-| The distance between two vectors. 160 | -} 161 | distance : Vec2 -> Vec2 -> Float 162 | distance = 163 | Native.Math.Vector2.distance 164 | 165 | 166 | {-| The square of the distance between two vectors. 167 | -} 168 | distanceSquared : Vec2 -> Vec2 -> Float 169 | distanceSquared = 170 | Native.Math.Vector2.distanceSquared 171 | 172 | 173 | {-| A unit vector with the same direction as the given vector: a / |a| 174 | -} 175 | normalize : Vec2 -> Vec2 176 | normalize = 177 | Native.Math.Vector2.normalize 178 | 179 | 180 | {-| Multiply the vector by a scalar: s * v 181 | -} 182 | scale : Float -> Vec2 -> Vec2 183 | scale = 184 | Native.Math.Vector2.scale 185 | 186 | 187 | {-| The dot product of a and b 188 | -} 189 | dot : Vec2 -> Vec2 -> Float 190 | dot = 191 | Native.Math.Vector2.dot 192 | -------------------------------------------------------------------------------- /src/Math/Vector4.elm: -------------------------------------------------------------------------------- 1 | module Math.Vector4 2 | exposing 3 | ( Vec4 4 | , vec4 5 | , getX 6 | , getY 7 | , getZ 8 | , getW 9 | , setX 10 | , setY 11 | , setZ 12 | , setW 13 | , add 14 | , sub 15 | , negate 16 | , scale 17 | , dot 18 | , normalize 19 | , direction 20 | , length 21 | , lengthSquared 22 | , distance 23 | , distanceSquared 24 | , toTuple 25 | , fromTuple 26 | , toRecord 27 | , fromRecord 28 | ) 29 | 30 | {-| A high performance linear algebra library using native JS arrays. Geared 31 | towards 3D graphics and use with `Graphics.WebGL`. All vectors are immutable. 32 | 33 | # Create 34 | @docs Vec4, vec4 35 | 36 | # Get and Set 37 | The set functions create a new copy of the vector, updating a single field. 38 | 39 | @docs getX, getY, getZ, getW, setX, setY, setZ, setW 40 | 41 | # Operations 42 | @docs add, sub, negate, scale, dot, normalize, direction, 43 | length, lengthSquared, distance, distanceSquared 44 | 45 | # Conversions 46 | @docs toTuple, fromTuple, toRecord, fromRecord 47 | -} 48 | 49 | import Native.Math.Vector4 50 | 51 | 52 | {-| Four dimensional vector type 53 | -} 54 | type Vec4 55 | = Vec4 56 | 57 | 58 | {-| Creates a new 4-element vector with the given x, y, z, and w values. 59 | -} 60 | vec4 : Float -> Float -> Float -> Float -> Vec4 61 | vec4 = 62 | Native.Math.Vector4.vec4 63 | 64 | 65 | {-| Extract the x component of a vector. 66 | -} 67 | getX : Vec4 -> Float 68 | getX = 69 | Native.Math.Vector4.getX 70 | 71 | 72 | {-| Extract the y component of a vector. 73 | -} 74 | getY : Vec4 -> Float 75 | getY = 76 | Native.Math.Vector4.getY 77 | 78 | 79 | {-| Extract the z component of a vector. 80 | -} 81 | getZ : Vec4 -> Float 82 | getZ = 83 | Native.Math.Vector4.getZ 84 | 85 | 86 | {-| Extract the w component of a vector. 87 | -} 88 | getW : Vec4 -> Float 89 | getW = 90 | Native.Math.Vector4.getW 91 | 92 | 93 | {-| Update the x component of a vector, returning a new vector. 94 | -} 95 | setX : Float -> Vec4 -> Vec4 96 | setX = 97 | Native.Math.Vector4.setX 98 | 99 | 100 | {-| Update the y component of a vector, returning a new vector. 101 | -} 102 | setY : Float -> Vec4 -> Vec4 103 | setY = 104 | Native.Math.Vector4.setY 105 | 106 | 107 | {-| Update the z component of a vector, returning a new vector. 108 | -} 109 | setZ : Float -> Vec4 -> Vec4 110 | setZ = 111 | Native.Math.Vector4.setZ 112 | 113 | 114 | {-| Update the w component of a vector, returning a new vector. 115 | -} 116 | setW : Float -> Vec4 -> Vec4 117 | setW = 118 | Native.Math.Vector4.setW 119 | 120 | 121 | {-| Convert a vector to a tuple. 122 | -} 123 | toTuple : Vec4 -> ( Float, Float, Float, Float ) 124 | toTuple = 125 | Native.Math.Vector4.toTuple 126 | 127 | 128 | {-| Convert a vector to a record. 129 | -} 130 | toRecord : Vec4 -> { x : Float, y : Float, z : Float, w : Float } 131 | toRecord = 132 | Native.Math.Vector4.toRecord 133 | 134 | 135 | {-| Convert a tuple to a vector. 136 | -} 137 | fromTuple : ( Float, Float, Float, Float ) -> Vec4 138 | fromTuple = 139 | Native.Math.Vector4.fromTuple 140 | 141 | 142 | {-| Convert a record to a vector. 143 | -} 144 | fromRecord : { x : Float, y : Float, z : Float, w : Float } -> Vec4 145 | fromRecord = 146 | Native.Math.Vector4.fromRecord 147 | 148 | 149 | {-| Vector addition: a + b 150 | -} 151 | add : Vec4 -> Vec4 -> Vec4 152 | add = 153 | Native.Math.Vector4.add 154 | 155 | 156 | {-| Vector subtraction: a - b 157 | -} 158 | sub : Vec4 -> Vec4 -> Vec4 159 | sub = 160 | Native.Math.Vector4.sub 161 | 162 | 163 | {-| Vector negation: -a 164 | -} 165 | negate : Vec4 -> Vec4 166 | negate = 167 | Native.Math.Vector4.neg 168 | 169 | 170 | {-| The normalized direction from b to a: (a - b) / |a - b| 171 | -} 172 | direction : Vec4 -> Vec4 -> Vec4 173 | direction = 174 | Native.Math.Vector4.direction 175 | 176 | 177 | {-| The length of the given vector: |a| 178 | -} 179 | length : Vec4 -> Float 180 | length = 181 | Native.Math.Vector4.length 182 | 183 | 184 | {-| The square of the length of the given vector: |a| * |a| 185 | -} 186 | lengthSquared : Vec4 -> Float 187 | lengthSquared = 188 | Native.Math.Vector4.lengthSquared 189 | 190 | 191 | {-| The distance between two vectors. 192 | -} 193 | distance : Vec4 -> Vec4 -> Float 194 | distance = 195 | Native.Math.Vector4.distance 196 | 197 | 198 | {-| The square of the distance between two vectors. 199 | -} 200 | distanceSquared : Vec4 -> Vec4 -> Float 201 | distanceSquared = 202 | Native.Math.Vector4.distanceSquared 203 | 204 | 205 | {-| A unit vector with the same direction as the given vector: a / |a| 206 | -} 207 | normalize : Vec4 -> Vec4 208 | normalize = 209 | Native.Math.Vector4.normalize 210 | 211 | 212 | {-| Multiply the vector by a scalar: s * v 213 | -} 214 | scale : Float -> Vec4 -> Vec4 215 | scale = 216 | Native.Math.Vector4.scale 217 | 218 | 219 | {-| The dot product of a and b 220 | -} 221 | dot : Vec4 -> Vec4 -> Float 222 | dot = 223 | Native.Math.Vector4.dot 224 | -------------------------------------------------------------------------------- /src/Math/Vector3.elm: -------------------------------------------------------------------------------- 1 | module Math.Vector3 2 | exposing 3 | ( Vec3 4 | , vec3 5 | , i 6 | , j 7 | , k 8 | , getX 9 | , getY 10 | , getZ 11 | , setX 12 | , setY 13 | , setZ 14 | , add 15 | , sub 16 | , negate 17 | , scale 18 | , dot 19 | , cross 20 | , normalize 21 | , direction 22 | , length 23 | , lengthSquared 24 | , distance 25 | , distanceSquared 26 | , toTuple 27 | , fromTuple 28 | , toRecord 29 | , fromRecord 30 | ) 31 | 32 | {-| A high performance linear algebra library using native JS arrays. Geared 33 | towards 3D graphics and use with `Graphics.WebGL`. All vectors are immutable. 34 | 35 | # Create 36 | @docs Vec3, vec3, i, j, k 37 | 38 | # Get and Set 39 | The set functions create a new copy of the vector, updating a single field. 40 | 41 | @docs getX, getY, getZ, setX, setY, setZ 42 | 43 | # Operations 44 | @docs add, sub, negate, scale, dot, cross, normalize, direction, 45 | length, lengthSquared, distance, distanceSquared 46 | 47 | # Conversions 48 | @docs toTuple, fromTuple, toRecord, fromRecord 49 | -} 50 | 51 | import Native.MJS 52 | 53 | 54 | {-| Three dimensional vector type 55 | -} 56 | type Vec3 57 | = Vec3 58 | 59 | 60 | {-| Creates a new 3-element vector with the given values. 61 | -} 62 | vec3 : Float -> Float -> Float -> Vec3 63 | vec3 = 64 | Native.MJS.vec3 65 | 66 | 67 | {-| The unit vector î which points in the x direction: `vec3 1 0 0` 68 | -} 69 | i : Vec3 70 | i = 71 | Native.MJS.vec3 1 0 0 72 | 73 | 74 | {-| The unit vector ĵ which points in the y direction: `vec3 0 1 0` 75 | -} 76 | j : Vec3 77 | j = 78 | Native.MJS.vec3 0 1 0 79 | 80 | 81 | {-| The unit vector k̂ which points in the z direction: `vec3 0 0 1` 82 | -} 83 | k : Vec3 84 | k = 85 | Native.MJS.vec3 0 0 1 86 | 87 | 88 | {-| Extract the x component of a vector. 89 | -} 90 | getX : Vec3 -> Float 91 | getX = 92 | Native.MJS.v3getX 93 | 94 | 95 | {-| Extract the y component of a vector. 96 | -} 97 | getY : Vec3 -> Float 98 | getY = 99 | Native.MJS.v3getY 100 | 101 | 102 | {-| Extract the z component of a vector. 103 | -} 104 | getZ : Vec3 -> Float 105 | getZ = 106 | Native.MJS.v3getZ 107 | 108 | 109 | {-| Update the x component of a vector, returning a new vector. 110 | -} 111 | setX : Float -> Vec3 -> Vec3 112 | setX = 113 | Native.MJS.v3setX 114 | 115 | 116 | {-| Update the y component of a vector, returning a new vector. 117 | -} 118 | setY : Float -> Vec3 -> Vec3 119 | setY = 120 | Native.MJS.v3setY 121 | 122 | 123 | {-| Update the z component of a vector, returning a new vector. 124 | -} 125 | setZ : Float -> Vec3 -> Vec3 126 | setZ = 127 | Native.MJS.v3setZ 128 | 129 | 130 | {-| Convert a vector to a tuple. 131 | -} 132 | toTuple : Vec3 -> ( Float, Float, Float ) 133 | toTuple = 134 | Native.MJS.toTuple3 135 | 136 | 137 | {-| Convert a vector to a record. 138 | -} 139 | toRecord : Vec3 -> { x : Float, y : Float, z : Float } 140 | toRecord = 141 | Native.MJS.toRecord3 142 | 143 | 144 | {-| Convert a tuple to a vector. 145 | -} 146 | fromTuple : ( Float, Float, Float ) -> Vec3 147 | fromTuple = 148 | Native.MJS.fromTuple3 149 | 150 | 151 | {-| Convert a record to a vector. 152 | -} 153 | fromRecord : { x : Float, y : Float, z : Float } -> Vec3 154 | fromRecord = 155 | Native.MJS.fromRecord3 156 | 157 | 158 | {-| Vector addition: a + b 159 | -} 160 | add : Vec3 -> Vec3 -> Vec3 161 | add = 162 | Native.MJS.v3add 163 | 164 | 165 | {-| Vector subtraction: a - b 166 | -} 167 | sub : Vec3 -> Vec3 -> Vec3 168 | sub = 169 | Native.MJS.v3sub 170 | 171 | 172 | {-| Vector negation: -a 173 | -} 174 | negate : Vec3 -> Vec3 175 | negate = 176 | Native.MJS.v3neg 177 | 178 | 179 | {-| The normalized direction from b to a: (a - b) / |a - b| 180 | -} 181 | direction : Vec3 -> Vec3 -> Vec3 182 | direction = 183 | Native.MJS.v3direction 184 | 185 | 186 | {-| The length of the given vector: |a| 187 | -} 188 | length : Vec3 -> Float 189 | length = 190 | Native.MJS.v3length 191 | 192 | 193 | {-| The square of the length of the given vector: |a| * |a| 194 | -} 195 | lengthSquared : Vec3 -> Float 196 | lengthSquared = 197 | Native.MJS.v3lengthSquared 198 | 199 | 200 | {-| The distance between two vectors. 201 | -} 202 | distance : Vec3 -> Vec3 -> Float 203 | distance = 204 | Native.MJS.v3distance 205 | 206 | 207 | {-| The square of the distance between two vectors. 208 | -} 209 | distanceSquared : Vec3 -> Vec3 -> Float 210 | distanceSquared = 211 | Native.MJS.v3distanceSquared 212 | 213 | 214 | {-| A unit vector with the same direction as the given vector: a / |a| 215 | -} 216 | normalize : Vec3 -> Vec3 217 | normalize = 218 | Native.MJS.v3normalize 219 | 220 | 221 | {-| Multiply the vector by a scalar: s * v 222 | -} 223 | scale : Float -> Vec3 -> Vec3 224 | scale = 225 | Native.MJS.v3scale 226 | 227 | 228 | {-| The dot product of a and b 229 | -} 230 | dot : Vec3 -> Vec3 -> Float 231 | dot = 232 | Native.MJS.v3dot 233 | 234 | 235 | {-| The cross product of a and b 236 | -} 237 | cross : Vec3 -> Vec3 -> Vec3 238 | cross = 239 | Native.MJS.v3cross 240 | -------------------------------------------------------------------------------- /src/Native/Math/Vector2.js: -------------------------------------------------------------------------------- 1 | 2 | /* 3 | * Copyright (c) 2010 Mozilla Corporation 4 | * Copyright (c) 2010 Vladimir Vukicevic 5 | * 6 | * Permission is hereby granted, free of charge, to any person 7 | * obtaining a copy of this software and associated documentation 8 | * files (the "Software"), to deal in the Software without 9 | * restriction, including without limitation the rights to use, 10 | * copy, modify, merge, publish, distribute, sublicense, and/or sell 11 | * copies of the Software, and to permit persons to whom the 12 | * Software is furnished to do so, subject to the following 13 | * conditions: 14 | * 15 | * The above copyright notice and this permission notice shall be 16 | * included in all copies or substantial portions of the Software. 17 | * 18 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 19 | * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES 20 | * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 21 | * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT 22 | * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, 23 | * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 24 | * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 25 | * OTHER DEALINGS IN THE SOFTWARE. 26 | */ 27 | 28 | /* 29 | * File: mjs 30 | * 31 | * Vector and Matrix math utilities for JavaScript, optimized for WebGL. 32 | * Edited to work with the Elm Programming Language 33 | */ 34 | 35 | var _elm_community$linear_algebra$Native_Math_Vector2 = function() { 36 | 37 | var MJS_FLOAT_ARRAY_TYPE = Float32Array; 38 | 39 | var V2 = { }; 40 | 41 | if (MJS_FLOAT_ARRAY_TYPE == Array) { 42 | V2.$ = function V2_$(x, y) { 43 | return [x, y]; 44 | }; 45 | } else { 46 | V2.$ = function V2_$(x, y) { 47 | return new MJS_FLOAT_ARRAY_TYPE([x, y]); 48 | }; 49 | } 50 | 51 | V2.getX = function V2_getX(a) { 52 | return a[0]; 53 | } 54 | V2.getY = function V2_getY(a) { 55 | return a[1]; 56 | } 57 | V2.setX = function V2_setX(x, a) { 58 | return new MJS_FLOAT_ARRAY_TYPE([x, a[1]]); 59 | } 60 | V2.setY = function V2_setY(y, a) { 61 | return new MJS_FLOAT_ARRAY_TYPE([a[0], y]); 62 | } 63 | 64 | V2.toTuple = function V2_toTuple(a) { 65 | return { 66 | ctor:"_Tuple2", 67 | _0:a[0], 68 | _1:a[1] 69 | }; 70 | }; 71 | V2.fromTuple = function V2_fromTuple(t) { 72 | return new MJS_FLOAT_ARRAY_TYPE([t._0, t._1]); 73 | }; 74 | 75 | V2.toRecord = function V2_toRecord(a) { 76 | return { 77 | _:{}, 78 | x:a[0], 79 | y:a[1] 80 | }; 81 | }; 82 | V2.fromRecord = function V2_fromRecord(r) { 83 | return new MJS_FLOAT_ARRAY_TYPE([r.x, r.y]); 84 | }; 85 | 86 | V2.add = function V2_add(a, b) { 87 | var r = new MJS_FLOAT_ARRAY_TYPE(2); 88 | r[0] = a[0] + b[0]; 89 | r[1] = a[1] + b[1]; 90 | return r; 91 | }; 92 | 93 | V2.sub = function V2_sub(a, b) { 94 | var r = new MJS_FLOAT_ARRAY_TYPE(2); 95 | r[0] = a[0] - b[0]; 96 | r[1] = a[1] - b[1]; 97 | return r; 98 | }; 99 | 100 | V2.neg = function V2_neg(a) { 101 | var r = new MJS_FLOAT_ARRAY_TYPE(2); 102 | r[0] = - a[0]; 103 | r[1] = - a[1]; 104 | return r; 105 | }; 106 | 107 | V2.direction = function V2_direction(a, b) { 108 | var r = new MJS_FLOAT_ARRAY_TYPE(2); 109 | r[0] = a[0] - b[0]; 110 | r[1] = a[1] - b[1]; 111 | var im = 1.0 / V2.length(r); 112 | r[0] = r[0] * im; 113 | r[1] = r[1] * im; 114 | return r; 115 | }; 116 | 117 | V2.length = function V2_length(a) { 118 | return Math.sqrt(a[0]*a[0] + a[1]*a[1]); 119 | }; 120 | 121 | V2.lengthSquared = function V2_lengthSquared(a) { 122 | return a[0]*a[0] + a[1]*a[1]; 123 | }; 124 | 125 | V2.distance = function V2_distance(a, b) { 126 | var dx = a[0] - b[0]; 127 | var dy = a[1] - b[1]; 128 | return Math.sqrt(dx * dx + dy * dy); 129 | }; 130 | 131 | V2.distanceSquared = function V2_distanceSquared(a, b) { 132 | var dx = a[0] - b[0]; 133 | var dy = a[1] - b[1]; 134 | return dx * dx + dy * dy; 135 | }; 136 | 137 | V2.normalize = function V2_normalize(a) { 138 | var r = new MJS_FLOAT_ARRAY_TYPE(2); 139 | var im = 1.0 / V2.length(a); 140 | r[0] = a[0] * im; 141 | r[1] = a[1] * im; 142 | return r; 143 | }; 144 | 145 | V2.scale = function V2_scale(k, a) { 146 | var r = new MJS_FLOAT_ARRAY_TYPE(2); 147 | r[0] = a[0] * k; 148 | r[1] = a[1] * k; 149 | return r; 150 | }; 151 | 152 | V2.dot = function V2_dot(a, b) { 153 | return a[0] * b[0] + a[1] * b[1]; 154 | }; 155 | 156 | return { 157 | vec2: F2(V2.$), 158 | getX: V2.getX, 159 | getY: V2.getY, 160 | setX: F2(V2.setX), 161 | setY: F2(V2.setY), 162 | toTuple: V2.toTuple, 163 | toRecord: V2.toRecord, 164 | fromTuple: V2.fromTuple, 165 | fromRecord: V2.fromRecord, 166 | add: F2(V2.add), 167 | sub: F2(V2.sub), 168 | neg: V2.neg, 169 | direction: F2(V2.direction), 170 | length: V2.length, 171 | lengthSquared: V2.lengthSquared, 172 | distance: F2(V2.distance), 173 | distanceSquared: F2(V2.distanceSquared), 174 | normalize: V2.normalize, 175 | scale: F2(V2.scale), 176 | dot: F2(V2.dot) 177 | }; 178 | 179 | }(); 180 | -------------------------------------------------------------------------------- /src/Native/Math/Vector4.js: -------------------------------------------------------------------------------- 1 | 2 | /* 3 | * Copyright (c) 2010 Mozilla Corporation 4 | * Copyright (c) 2010 Vladimir Vukicevic 5 | * 6 | * Permission is hereby granted, free of charge, to any person 7 | * obtaining a copy of this software and associated documentation 8 | * files (the "Software"), to deal in the Software without 9 | * restriction, including without limitation the rights to use, 10 | * copy, modify, merge, publish, distribute, sublicense, and/or sell 11 | * copies of the Software, and to permit persons to whom the 12 | * Software is furnished to do so, subject to the following 13 | * conditions: 14 | * 15 | * The above copyright notice and this permission notice shall be 16 | * included in all copies or substantial portions of the Software. 17 | * 18 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 19 | * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES 20 | * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 21 | * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT 22 | * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, 23 | * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 24 | * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 25 | * OTHER DEALINGS IN THE SOFTWARE. 26 | */ 27 | 28 | /* 29 | * File: mjs 30 | * 31 | * Vector and Matrix math utilities for JavaScript, optimized for WebGL. 32 | * Edited to work with the Elm Programming Language 33 | */ 34 | 35 | var _elm_community$linear_algebra$Native_Math_Vector4 = function() { 36 | 37 | var MJS_FLOAT_ARRAY_TYPE = Float32Array; 38 | 39 | var V4 = { }; 40 | 41 | if (MJS_FLOAT_ARRAY_TYPE == Array) { 42 | V4.$ = function V4_$(x, y, z, w) { 43 | return [x, y, z, w]; 44 | }; 45 | } else { 46 | V4.$ = function V4_$(x, y, z, w) { 47 | return new MJS_FLOAT_ARRAY_TYPE([x, y, z, w]); 48 | }; 49 | } 50 | 51 | V4.getX = function V4_getX(a) { 52 | return a[0]; 53 | } 54 | V4.getY = function V4_getY(a) { 55 | return a[1]; 56 | } 57 | V4.getZ = function V4_getZ(a) { 58 | return a[2]; 59 | } 60 | V4.getW = function V4_getW(a) { 61 | return a[3]; 62 | } 63 | V4.setX = function V4_setX(x, a) { 64 | return new MJS_FLOAT_ARRAY_TYPE([x, a[1], a[2], a[3]]); 65 | } 66 | V4.setY = function V4_setY(y, a) { 67 | return new MJS_FLOAT_ARRAY_TYPE([a[0], y, a[2], a[3]]); 68 | } 69 | V4.setZ = function V4_setZ(z, a) { 70 | return new MJS_FLOAT_ARRAY_TYPE([a[0], a[1], z, a[3]]); 71 | } 72 | V4.setW = function V4_setW(w, a) { 73 | return new MJS_FLOAT_ARRAY_TYPE([a[0], a[1], a[2], w]); 74 | } 75 | 76 | V4.toTuple = function V4_toTuple(a) { 77 | return { 78 | ctor:"_Tuple4", 79 | _0:a[0], 80 | _1:a[1], 81 | _2:a[2], 82 | _3:a[3] 83 | }; 84 | }; 85 | V4.fromTuple = function V4_fromTuple(t) { 86 | return new MJS_FLOAT_ARRAY_TYPE([t._0, t._1, t._2, t._3]); 87 | }; 88 | 89 | V4.toRecord = function V4_toRecord(a) { 90 | return { 91 | _:{}, 92 | x:a[0], 93 | y:a[1], 94 | z:a[2], 95 | w:a[3] 96 | }; 97 | }; 98 | V4.fromRecord = function V4_fromRecord(r) { 99 | return new MJS_FLOAT_ARRAY_TYPE([r.x, r.y, r.z, r.w]); 100 | }; 101 | 102 | V4.add = function V4_add(a, b) { 103 | var r = new MJS_FLOAT_ARRAY_TYPE(4); 104 | r[0] = a[0] + b[0]; 105 | r[1] = a[1] + b[1]; 106 | r[2] = a[2] + b[2]; 107 | r[3] = a[3] + b[3]; 108 | return r; 109 | }; 110 | 111 | V4.sub = function V4_sub(a, b) { 112 | var r = new MJS_FLOAT_ARRAY_TYPE(4); 113 | r[0] = a[0] - b[0]; 114 | r[1] = a[1] - b[1]; 115 | r[2] = a[2] - b[2]; 116 | r[3] = a[3] - b[3]; 117 | return r; 118 | }; 119 | 120 | V4.neg = function V4_neg(a) { 121 | var r = new MJS_FLOAT_ARRAY_TYPE(4); 122 | r[0] = - a[0]; 123 | r[1] = - a[1]; 124 | r[2] = - a[2]; 125 | r[3] = - a[3]; 126 | return r; 127 | }; 128 | 129 | V4.direction = function V4_direction(a, b) { 130 | var r = new MJS_FLOAT_ARRAY_TYPE(4); 131 | r[0] = a[0] - b[0]; 132 | r[1] = a[1] - b[1]; 133 | r[2] = a[2] - b[2]; 134 | r[3] = a[3] - b[3]; 135 | var im = 1.0 / V4.length(r); 136 | r[0] = r[0] * im; 137 | r[1] = r[1] * im; 138 | r[2] = r[2] * im; 139 | r[3] = r[3] * im; 140 | return r; 141 | }; 142 | 143 | V4.length = function V4_length(a) { 144 | return Math.sqrt(a[0]*a[0] + a[1]*a[1] + a[2]*a[2] + a[3]*a[3]); 145 | }; 146 | 147 | V4.lengthSquared = function V4_lengthSquared(a) { 148 | return a[0]*a[0] + a[1]*a[1] + a[2]*a[2] + a[3]*a[3]; 149 | }; 150 | 151 | V4.distance = function V4_distance(a, b) { 152 | var dx = a[0] - b[0]; 153 | var dy = a[1] - b[1]; 154 | var dz = a[2] - b[2]; 155 | var dw = a[3] - b[3]; 156 | return Math.sqrt(dx * dx + dy * dy + dz * dz + dw * dw); 157 | }; 158 | 159 | V4.distanceSquared = function V4_distanceSquared(a, b) { 160 | var dx = a[0] - b[0]; 161 | var dy = a[1] - b[1]; 162 | var dz = a[2] - b[2]; 163 | var dw = a[3] - b[3]; 164 | return dx * dx + dy * dy + dz * dz + dw * dw; 165 | }; 166 | 167 | V4.normalize = function V4_normalize(a) { 168 | var r = new MJS_FLOAT_ARRAY_TYPE(4); 169 | var im = 1.0 / V4.length(a); 170 | r[0] = a[0] * im; 171 | r[1] = a[1] * im; 172 | r[2] = a[2] * im; 173 | r[3] = a[3] * im; 174 | return r; 175 | }; 176 | 177 | V4.scale = function V4_scale(k, a) { 178 | var r = new MJS_FLOAT_ARRAY_TYPE(4); 179 | r[0] = a[0] * k; 180 | r[1] = a[1] * k; 181 | r[2] = a[2] * k; 182 | r[3] = a[3] * k; 183 | return r; 184 | }; 185 | 186 | V4.dot = function V4_dot(a, b) { 187 | return a[0] * b[0] + a[1] * b[1] + a[2] * b[2] + a[3] * b[3]; 188 | }; 189 | 190 | return { 191 | vec4: F4(V4.$), 192 | getX: V4.getX, 193 | getY: V4.getY, 194 | getZ: V4.getZ, 195 | getW: V4.getW, 196 | setX: F2(V4.setX), 197 | setY: F2(V4.setY), 198 | setZ: F2(V4.setZ), 199 | setW: F2(V4.setW), 200 | toTuple: V4.toTuple, 201 | toRecord: V4.toRecord, 202 | fromTuple: V4.fromTuple, 203 | fromRecord: V4.fromRecord, 204 | add: F2(V4.add), 205 | sub: F2(V4.sub), 206 | neg: V4.neg, 207 | direction: F2(V4.direction), 208 | length: V4.length, 209 | lengthSquared: V4.lengthSquared, 210 | distance: F2(V4.distance), 211 | distanceSquared: F2(V4.distanceSquared), 212 | normalize: V4.normalize, 213 | scale: F2(V4.scale), 214 | dot: F2(V4.dot) 215 | }; 216 | 217 | }(); 218 | -------------------------------------------------------------------------------- /src/Math/Matrix4.elm: -------------------------------------------------------------------------------- 1 | module Math.Matrix4 2 | exposing 3 | ( Mat4 4 | , identity 5 | , fromRecord 6 | , toRecord 7 | , makeFromList 8 | , inverse 9 | , inverseOrthonormal 10 | , mul 11 | , mulAffine 12 | , transpose 13 | , makeBasis 14 | , transform 15 | , makeFrustum 16 | , makePerspective 17 | , makeOrtho 18 | , makeOrtho2D 19 | , makeLookAt 20 | , rotate 21 | , scale 22 | , scale3 23 | , translate 24 | , translate3 25 | , makeRotate 26 | , makeScale 27 | , makeScale3 28 | , makeTranslate 29 | , makeTranslate3 30 | ) 31 | 32 | {-| A high performance linear algebra library using native JS arrays. Geared 33 | towards 3D graphics and use with `Graphics.WebGL`. All matrices are immutable. 34 | 35 | This library uses the convention that the prefix `make` is creating a new 36 | array,as without the prefix, you are applying some transform to an 37 | existing matrix. 38 | 39 | # Create 40 | 41 | @docs Mat4, identity, makeFromList 42 | 43 | # Operations 44 | 45 | @docs inverse, inverseOrthonormal, mul, mulAffine, transpose, makeBasis, transform 46 | 47 | # Projections 48 | 49 | @docs makeFrustum, makePerspective, makeOrtho, makeOrtho2D, makeLookAt 50 | 51 | # Apply Transformations 52 | 53 | @docs rotate, scale, scale3, translate, translate3 54 | 55 | # Create Transformations 56 | 57 | @docs makeRotate, makeScale, makeScale3, makeTranslate, makeTranslate3 58 | 59 | # Conversions 60 | 61 | @docs toRecord, fromRecord 62 | 63 | -} 64 | 65 | import Native.MJS 66 | import Math.Vector3 exposing (Vec3) 67 | 68 | 69 | {-| 4x4 matrix type 70 | -} 71 | type Mat4 72 | = Mat4 73 | 74 | 75 | {-| Multiply a vector by a 4x4 matrix: m * v 76 | -} 77 | transform : Mat4 -> Vec3 -> Vec3 78 | transform = 79 | Native.MJS.v3mul4x4 80 | 81 | 82 | {-| A matrix with all 0s, except 1s on the diagonal. 83 | -} 84 | identity : Mat4 85 | identity = 86 | Native.MJS.m4x4identity 87 | 88 | 89 | {-| Computes the inverse of any matrix. This is somewhat computationally 90 | intensive. If the matrix is not invertible, `Nothing` is returned. 91 | -} 92 | inverse : Mat4 -> Maybe Mat4 93 | inverse = 94 | Native.MJS.m4x4inverse 95 | 96 | 97 | {-| Computes the inverse of the given matrix, assuming that the matrix is 98 | orthonormal. This algorithm is more efficient than general matrix inversion, and 99 | has no possibility of failing. 100 | -} 101 | inverseOrthonormal : Mat4 -> Mat4 102 | inverseOrthonormal = 103 | Native.MJS.m4x4inverseOrthonormal 104 | 105 | 106 | {-| Creates a matrix for a projection frustum with the given parameters. 107 | 108 | Parameters: 109 | 110 | * left - the left coordinate of the frustum 111 | * right- the right coordinate of the frustum 112 | * bottom - the bottom coordinate of the frustum 113 | * top - the top coordinate of the frustum 114 | * znear - the near z distance of the frustum 115 | * zfar - the far z distance of the frustum 116 | -} 117 | makeFrustum : Float -> Float -> Float -> Float -> Float -> Float -> Mat4 118 | makeFrustum = 119 | Native.MJS.m4x4makeFrustum 120 | 121 | 122 | {-| Creates a matrix for a perspective projection with the given parameters. 123 | 124 | Parameters: 125 | 126 | * fovy - field of view in the y axis, in degrees 127 | * aspect - aspect ratio 128 | * znear - the near z distance of the projection 129 | * zfar - the far z distance of the projection 130 | -} 131 | makePerspective : Float -> Float -> Float -> Float -> Mat4 132 | makePerspective = 133 | Native.MJS.m4x4makePerspective 134 | 135 | 136 | {-| 137 | Creates a matrix for an orthogonal frustum projection with the given parameters. 138 | 139 | Parameters: 140 | 141 | * left - the left coordinate of the frustum 142 | * right- the right coordinate of the frustum 143 | * bottom - the bottom coordinate of the frustum 144 | * top - the top coordinate of the frustum 145 | * znear - the near z distance of the frustum 146 | * zfar - the far z distance of the frustum 147 | -} 148 | makeOrtho : Float -> Float -> Float -> Float -> Float -> Float -> Mat4 149 | makeOrtho = 150 | Native.MJS.m4x4makeOrtho 151 | 152 | 153 | {-| Creates a matrix for a 2D orthogonal frustum projection with the given 154 | parameters. `znear` and `zfar` are assumed to be -1 and 1, respectively. 155 | 156 | Parameters: 157 | 158 | * left - the left coordinate of the frustum 159 | * right- the right coordinate of the frustum 160 | * bottom - the bottom coordinate of the frustum 161 | * top - the top coordinate of the frustum 162 | -} 163 | makeOrtho2D : Float -> Float -> Float -> Float -> Mat4 164 | makeOrtho2D = 165 | Native.MJS.m4x4makeOrtho2D 166 | 167 | 168 | {-| Matrix multiplcation: a * b 169 | -} 170 | mul : Mat4 -> Mat4 -> Mat4 171 | mul = 172 | Native.MJS.m4x4mul 173 | 174 | 175 | {-| Matrix multiplication, assuming a and b are affine: a * b 176 | -} 177 | mulAffine : Mat4 -> Mat4 -> Mat4 178 | mulAffine = 179 | Native.MJS.m4x4mulAffine 180 | 181 | 182 | {-| Creates a transformation matrix for rotation in radians about the 183 | 3-element vector axis. 184 | -} 185 | makeRotate : Float -> Vec3 -> Mat4 186 | makeRotate = 187 | Native.MJS.m4x4makeRotate 188 | 189 | 190 | {-| Concatenates a rotation in radians about an axis to the given matrix. 191 | -} 192 | rotate : Float -> Vec3 -> Mat4 -> Mat4 193 | rotate = 194 | Native.MJS.m4x4rotate 195 | 196 | 197 | {-| Creates a transformation matrix for scaling by 3 scalar values, one for 198 | each of the x, y, and z directions. 199 | -} 200 | makeScale3 : Float -> Float -> Float -> Mat4 201 | makeScale3 = 202 | Native.MJS.m4x4makeScale3 203 | 204 | 205 | {-| Creates a transformation matrix for scaling each of the x, y, and z axes by 206 | the amount given in the corresponding element of the 3-element vector. 207 | -} 208 | makeScale : Vec3 -> Mat4 209 | makeScale = 210 | Native.MJS.m4x4makeScale 211 | 212 | 213 | {-| Concatenates a scaling to the given matrix. 214 | -} 215 | scale3 : Float -> Float -> Float -> Mat4 -> Mat4 216 | scale3 = 217 | Native.MJS.m4x4scale3 218 | 219 | 220 | {-| Concatenates a scaling to the given matrix. 221 | -} 222 | scale : Vec3 -> Mat4 -> Mat4 223 | scale = 224 | Native.MJS.m4x4scale 225 | 226 | 227 | {-| 228 | Creates a transformation matrix for translating by 3 scalar values, one for 229 | each of the x, y, and z directions. 230 | -} 231 | makeTranslate3 : Float -> Float -> Float -> Mat4 232 | makeTranslate3 = 233 | Native.MJS.m4x4makeTranslate3 234 | 235 | 236 | {-| Creates a transformation matrix for translating each of the x, y, and z 237 | axes by the amount given in the corresponding element of the 3-element vector. 238 | -} 239 | makeTranslate : Vec3 -> Mat4 240 | makeTranslate = 241 | Native.MJS.m4x4makeTranslate 242 | 243 | 244 | {-| 245 | Concatenates a translation to the given matrix. 246 | -} 247 | translate3 : Float -> Float -> Float -> Mat4 -> Mat4 248 | translate3 = 249 | Native.MJS.m4x4translate3 250 | 251 | 252 | {-| 253 | Concatenates a translation to the given matrix. 254 | -} 255 | translate : Vec3 -> Mat4 -> Mat4 256 | translate = 257 | Native.MJS.m4x4translate 258 | 259 | 260 | {-| 261 | Creates a transformation matrix for a camera. 262 | 263 | Parameters: 264 | 265 | * eye - The location of the camera 266 | * center - The location of the focused object 267 | * up - The "up" direction according to the camera 268 | -} 269 | makeLookAt : Vec3 -> Vec3 -> Vec3 -> Mat4 270 | makeLookAt = 271 | Native.MJS.m4x4makeLookAt 272 | 273 | 274 | {-| "Flip" the matrix across the diagonal by swapping row index and column 275 | index. 276 | -} 277 | transpose : Mat4 -> Mat4 278 | transpose = 279 | Native.MJS.m4x4transpose 280 | 281 | 282 | {-| Creates a transform from a basis consisting of 3 linearly independent vectors. 283 | -} 284 | makeBasis : Vec3 -> Vec3 -> Vec3 -> Mat4 285 | makeBasis = 286 | Native.MJS.m4x4makeBasis 287 | 288 | 289 | {-| Creates a matrix from a list of elements. Returns Nothing if the length of 290 | the list is not exactly 16 (4x4). 291 | -} 292 | makeFromList : List Float -> Maybe Mat4 293 | makeFromList = 294 | Native.MJS.m4x4fromList 295 | 296 | 297 | {-| Convert a matrix to a record. 298 | -} 299 | toRecord : Mat4 -> { m11 : Float, m21 : Float, m31 : Float, m41 : Float, m12 : Float, m22 : Float, m32 : Float, m42 : Float, m13 : Float, m23 : Float, m33 : Float, m43 : Float, m14 : Float, m24 : Float, m34 : Float, m44 : Float } 300 | toRecord = 301 | Native.MJS.m4x4toRecord 302 | 303 | 304 | {-| Convert a record to a matrix. 305 | -} 306 | fromRecord : { m11 : Float, m21 : Float, m31 : Float, m41 : Float, m12 : Float, m22 : Float, m32 : Float, m42 : Float, m13 : Float, m23 : Float, m33 : Float, m43 : Float, m14 : Float, m24 : Float, m34 : Float, m44 : Float } -> Mat4 307 | fromRecord = 308 | Native.MJS.m4x4fromRecord 309 | -------------------------------------------------------------------------------- /tests/Tests.elm: -------------------------------------------------------------------------------- 1 | module Tests exposing (suite) 2 | 3 | import Expect 4 | import Fuzz 5 | import Math.Matrix4 as M4 6 | import Math.Vector2 as V2 7 | import Math.Vector3 as V3 8 | import Math.Vector4 as V4 9 | import Test exposing (Test, describe, fuzz, fuzz3, test) 10 | 11 | 12 | suite : Test 13 | suite = 14 | describe "elm-linear-algebra" 15 | [ describe "Vector2 module" 16 | [ test "vec2" <| 17 | \() -> 18 | Expect.equal 19 | (V2.vec2 3 4) 20 | (V2.vec2 3 4) 21 | , test "setX" <| 22 | \() -> 23 | Expect.equal 24 | (V2.vec2 5 4) 25 | (V2.vec2 3 4 |> V2.setX 5) 26 | , test "setY" <| 27 | \() -> 28 | Expect.equal 29 | (V2.vec2 3 6) 30 | (V2.vec2 3 4 |> V2.setY 6) 31 | ] 32 | , describe "Vector4 module" 33 | [ test "vec4" <| 34 | \() -> 35 | Expect.equal 36 | (V4.vec4 1 2 3 4) 37 | (V4.vec4 1 2 3 4) 38 | , test "setX" <| 39 | \() -> 40 | Expect.equal 41 | (V4.vec4 5 2 3 4) 42 | (V4.vec4 1 2 3 4 |> V4.setX 5) 43 | , test "setY" <| 44 | \() -> 45 | Expect.equal 46 | (V4.vec4 1 6 3 4) 47 | (V4.vec4 1 2 3 4 |> V4.setY 6) 48 | , test "setZ" <| 49 | \() -> 50 | Expect.equal 51 | (V4.vec4 1 2 7 4) 52 | (V4.vec4 1 2 3 4 |> V4.setZ 7) 53 | , test "setW" <| 54 | \() -> 55 | Expect.equal 56 | (V4.vec4 1 2 3 8) 57 | (V4.vec4 1 2 3 4 |> V4.setW 8) 58 | ] 59 | , describe "Matrix4 module" 60 | [ describe "inverse" 61 | [ test "Identity is its own inverse" <| 62 | \_ -> 63 | M4.inverse M4.identity |> Expect.equal (Just M4.identity) 64 | , test "Scaling in 3D inverts to shrinking" <| 65 | \_ -> 66 | M4.makeScale3 2 3 (1 / 8) 67 | |> M4.inverse 68 | |> Expect.equal (Just (M4.makeScale3 0.5 (1 / 3) 8)) 69 | , fuzz3 Fuzz.float Fuzz.float Fuzz.float "Translating in 3D inverts to translating the other way" <| 70 | \x y z -> 71 | M4.makeTranslate3 x y z 72 | |> M4.inverse 73 | |> Expect.equal (Just (M4.makeTranslate3 -x -y -z)) 74 | , Test.concat <| 75 | -- using constants instead of fuzz because of floating point errors 76 | flip List.map 77 | [ pi, 1.5 * pi, pi / 12, pi / 50 ] 78 | (\theta -> 79 | test ("Rotation by " ++ toString theta) <| 80 | \_ -> 81 | let 82 | m = 83 | M4.makeRotate theta V3.i 84 | in 85 | m 86 | |> M4.inverse 87 | |> Maybe.map (M4.mul m) 88 | |> Expect.equal (Just M4.identity) 89 | ) 90 | , test "cannot invert a singular matrix" <| 91 | \_ -> 92 | M4.makeBasis V3.i V3.j (V3.fromTuple ( 0, 0, 0 )) 93 | |> M4.inverse 94 | |> Expect.equal Nothing 95 | , test "inverts a known matrix" <| 96 | \_ -> 97 | M4.makeBasis 98 | (V3.fromTuple ( 2, 9, -3 )) 99 | (V3.fromTuple ( -4, 3, 14 )) 100 | (V3.fromTuple ( 1, 12, 6 )) 101 | |> M4.inverse 102 | |> Expect.equal 103 | (M4.makeBasis 104 | (V3.fromTuple ( -150, -90, 135 )) 105 | (V3.fromTuple ( 38, 15, -16 )) 106 | (V3.fromTuple ( -51, -15, 42 )) 107 | |> M4.scale3 (1 / 195) (1 / 195) (1 / 195) 108 | |> Just 109 | ) 110 | , test "makeFromList should be able create identity matrix" <| 111 | \_ -> 112 | M4.makeFromList [ 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1 ] |> Expect.equal (Just M4.identity) 113 | , test "makeFromList should return Nothing for short list of elements" <| 114 | \_ -> 115 | M4.makeFromList [] |> Expect.equal Nothing 116 | , test "makeFromList should return Nothing for too long list of elements" <| 117 | \_ -> 118 | M4.makeFromList [ 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 1 ] |> Expect.equal Nothing 119 | , test "fromRecord should be able to create the identity matrix" <| 120 | \_ -> 121 | M4.fromRecord { m11 = 1, m21 = 0, m31 = 0, m41 = 0, m12 = 0, m22 = 1, m32 = 0, m42 = 0, m13 = 0, m23 = 0, m33 = 1, m43 = 0, m14 = 0, m24 = 0, m34 = 0, m44 = 1 } |> Expect.equal M4.identity 122 | , test "toRecord should convert the identity matrix" <| 123 | \_ -> 124 | { m11 = 1, m21 = 0, m31 = 0, m41 = 0, m12 = 0, m22 = 1, m32 = 0, m42 = 0, m13 = 0, m23 = 0, m33 = 1, m43 = 0, m14 = 0, m24 = 0, m34 = 0, m44 = 1 } |> Expect.equal (M4.toRecord M4.identity) 125 | , fuzz fuzz4x4 "fromRecord should be the opposite of toRecord" <| 126 | \record4x4 -> 127 | M4.toRecord (M4.fromRecord record4x4) |> Expect.equal record4x4 128 | , test "matrix from list should not lose precision" <| 129 | \_ -> 130 | let 131 | matrix = 132 | M4.makeFromList 133 | [ 0.0007645259938837921, 0, 0, 0, 0, 0.0007645259938837921, 0, 0, -178844.39532879056, -115444.72328862673, -23930.400791413915, -0.4996215217852649, 179114.76199136386, 115619.29560235815, 23930.038231557068, 0.5003784782148529 ] 134 | in 135 | matrix 136 | |> toString 137 | |> Expect.equal "Just { 0 = 0.0007645259938837921, 1 = 0, 2 = 0, 3 = 0, 4 = 0, 5 = 0.0007645259938837921, 6 = 0, 7 = 0, 8 = -178844.39532879056, 9 = -115444.72328862673, 10 = -23930.400791413915, 11 = -0.4996215217852649, 12 = 179114.76199136386, 13 = 115619.29560235815, 14 = 23930.038231557068, 15 = 0.5003784782148529 }" 138 | , test "matrix make basis should not lose precision" <| 139 | \_ -> 140 | let 141 | matrix = 142 | M4.makeBasis 143 | (V3.fromTuple ( 0.0007645259938837921, 0, 0 )) 144 | (V3.fromTuple ( 0, 0, 0 )) 145 | (V3.fromTuple ( 0, 0, -178844.39532879056 )) 146 | in 147 | matrix 148 | |> toString 149 | |> Expect.equal "{ 0 = 0.0007645259938837921, 1 = 0, 2 = 0, 3 = 0, 4 = 0, 5 = 0, 6 = 0, 7 = 0, 8 = 0, 9 = 0, 10 = -178844.39532879056, 11 = 0, 12 = 0, 13 = 0, 14 = 0, 15 = 1 }" 150 | ] 151 | ] 152 | ] 153 | 154 | 155 | fuzz4x4 : Fuzz.Fuzzer { m11 : Float, m21 : Float, m31 : Float, m41 : Float, m12 : Float, m22 : Float, m32 : Float, m42 : Float, m13 : Float, m23 : Float, m33 : Float, m43 : Float, m14 : Float, m24 : Float, m34 : Float, m44 : Float } 156 | fuzz4x4 = 157 | Fuzz.map 158 | (\m11 m21 m31 m41 m12 m22 m32 m42 m13 m23 m33 m43 m14 m24 m34 m44 -> 159 | { m11 = m11 160 | , m21 = m21 161 | , m31 = m31 162 | , m41 = m41 163 | , m12 = m12 164 | , m22 = m22 165 | , m32 = m32 166 | , m42 = m42 167 | , m13 = m13 168 | , m23 = m23 169 | , m33 = m33 170 | , m43 = m43 171 | , m14 = m14 172 | , m24 = m24 173 | , m34 = m34 174 | , m44 = m44 175 | } 176 | ) 177 | Fuzz.float 178 | |> Fuzz.andMap Fuzz.float 179 | |> Fuzz.andMap Fuzz.float 180 | |> Fuzz.andMap Fuzz.float 181 | |> Fuzz.andMap Fuzz.float 182 | |> Fuzz.andMap Fuzz.float 183 | |> Fuzz.andMap Fuzz.float 184 | |> Fuzz.andMap Fuzz.float 185 | |> Fuzz.andMap Fuzz.float 186 | |> Fuzz.andMap Fuzz.float 187 | |> Fuzz.andMap Fuzz.float 188 | |> Fuzz.andMap Fuzz.float 189 | |> Fuzz.andMap Fuzz.float 190 | |> Fuzz.andMap Fuzz.float 191 | |> Fuzz.andMap Fuzz.float 192 | |> Fuzz.andMap Fuzz.float 193 | -------------------------------------------------------------------------------- /src/Native/MJS.js: -------------------------------------------------------------------------------- 1 | 2 | /* 3 | * Copyright (c) 2010 Mozilla Corporation 4 | * Copyright (c) 2010 Vladimir Vukicevic 5 | * Copyright (c) 2013 John Mayer 6 | * 7 | * Permission is hereby granted, free of charge, to any person 8 | * obtaining a copy of this software and associated documentation 9 | * files (the "Software"), to deal in the Software without 10 | * restriction, including without limitation the rights to use, 11 | * copy, modify, merge, publish, distribute, sublicense, and/or sell 12 | * copies of the Software, and to permit persons to whom the 13 | * Software is furnished to do so, subject to the following 14 | * conditions: 15 | * 16 | * The above copyright notice and this permission notice shall be 17 | * included in all copies or substantial portions of the Software. 18 | * 19 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 20 | * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES 21 | * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 22 | * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT 23 | * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, 24 | * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 25 | * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 26 | * OTHER DEALINGS IN THE SOFTWARE. 27 | */ 28 | 29 | /* 30 | * File: mjs 31 | * 32 | * Vector and Matrix math utilities for JavaScript, optimized for WebGL. 33 | * Edited to work with the Elm Programming Language 34 | */ 35 | 36 | var _elm_community$linear_algebra$Native_MJS = function() { 37 | 38 | 39 | /* 40 | * Constant: MJS_VERSION 41 | * 42 | * mjs version number aa.bb.cc, encoded as an integer of the form: 43 | * 0xaabbcc. 44 | */ 45 | var MJS_VERSION = 0x000000; 46 | 47 | /* 48 | * Constant: MJS_DO_ASSERT 49 | * 50 | * Enables or disables runtime assertions. 51 | * 52 | * For potentially more performance, the assert methods can be 53 | * commented out in each place where they are called. 54 | */ 55 | // var MJS_DO_ASSERT = false; 56 | 57 | /* 58 | * Constant: MJS_FLOAT_ARRAY_TYPE 59 | * 60 | * The base float array type. By default, WebGLFloatArray. 61 | * 62 | * mjs can work with any array-like elements, but if an array 63 | * creation is requested, it will create an array of the type 64 | * MJS_FLOAT_ARRAY_TYPE. Also, the builtin constants such as (M4x4.I) 65 | * will be of this type. 66 | */ 67 | //MJS_FLOAT_ARRAY_TYPE = WebGLFloatArray; 68 | //MJS_FLOAT_ARRAY_TYPE = Float32Array; 69 | var MJS_FLOAT_ARRAY_TYPE = Float64Array; 70 | //MJS_FLOAT_ARRAY_TYPE = Array; 71 | 72 | /* 73 | if (MJS_DO_ASSERT) { 74 | function MathUtils_assert(cond, msg) { 75 | if (!cond) { 76 | throw "Assertion failed: " + msg; 77 | } 78 | } 79 | } else { 80 | */ 81 | function MathUtils_assert() { } 82 | //} 83 | 84 | /* 85 | * Class: V3 86 | * 87 | * Methods for working with 3-element vectors. A vector is represented by a 3-element array. 88 | * Any valid JavaScript array type may be used, but if new 89 | * vectors are created they are created using the configured MJS_FLOAT_ARRAY_TYPE. 90 | */ 91 | 92 | var V3 = { }; 93 | 94 | V3._temp1 = new MJS_FLOAT_ARRAY_TYPE(3); 95 | V3._temp2 = new MJS_FLOAT_ARRAY_TYPE(3); 96 | V3._temp3 = new MJS_FLOAT_ARRAY_TYPE(3); 97 | 98 | if (MJS_FLOAT_ARRAY_TYPE == Array) { 99 | V3.x = [1.0, 0.0, 0.0]; 100 | V3.y = [0.0, 1.0, 0.0]; 101 | V3.z = [0.0, 0.0, 1.0]; 102 | 103 | V3.$ = function V3_$(x, y, z) { 104 | return [x, y, z]; 105 | }; 106 | } else { 107 | V3.x = new MJS_FLOAT_ARRAY_TYPE([1.0, 0.0, 0.0]); 108 | V3.y = new MJS_FLOAT_ARRAY_TYPE([0.0, 1.0, 0.0]); 109 | V3.z = new MJS_FLOAT_ARRAY_TYPE([0.0, 0.0, 1.0]); 110 | 111 | /* 112 | * Function: V3.$ 113 | * 114 | * Creates a new 3-element vector with the given values. 115 | * 116 | * Parameters: 117 | * 118 | * x,y,z - the 3 elements of the new vector. 119 | * 120 | * Returns: 121 | * 122 | * A new vector containing with the given argument values. 123 | */ 124 | 125 | V3.$ = function V3_$(x, y, z) { 126 | return new MJS_FLOAT_ARRAY_TYPE([x, y, z]); 127 | }; 128 | } 129 | 130 | V3.u = V3.x; 131 | V3.v = V3.y; 132 | 133 | V3.getX = function V3_getX(a) { 134 | return a[0]; 135 | } 136 | V3.getY = function V3_getY(a) { 137 | return a[1]; 138 | } 139 | V3.getZ = function V3_getZ(a) { 140 | return a[2]; 141 | } 142 | V3.setX = function V3_setX(x, a) { 143 | return new MJS_FLOAT_ARRAY_TYPE([x, a[1], a[2]]); 144 | } 145 | V3.setY = function V3_setY(y, a) { 146 | return new MJS_FLOAT_ARRAY_TYPE([a[0], y, a[2]]); 147 | } 148 | V3.setZ = function V3_setZ(z, a) { 149 | return new MJS_FLOAT_ARRAY_TYPE([a[0], a[1], z]); 150 | } 151 | 152 | V3.toTuple3 = function V3_toTuple3(a) { 153 | return { 154 | ctor:"_Tuple3", 155 | _0:a[0], 156 | _1:a[1], 157 | _2:a[2] 158 | }; 159 | }; 160 | V3.fromTuple3 = function V3_fromTuple3(t) { 161 | return new MJS_FLOAT_ARRAY_TYPE([t._0, t._1, t._2]); 162 | }; 163 | 164 | V3.toRecord3 = function V3_toRecord3(a) { 165 | return { 166 | _:{}, 167 | x:a[0], 168 | y:a[1], 169 | z:a[2] 170 | }; 171 | }; 172 | V3.fromRecord3 = function V3_fromRecord3(r) { 173 | return new MJS_FLOAT_ARRAY_TYPE([r.x, r.y, r.z]); 174 | }; 175 | 176 | /* 177 | * Function: V3.add 178 | * 179 | * Perform r = a + b. 180 | * 181 | * Parameters: 182 | * 183 | * a - the first vector operand 184 | * b - the second vector operand 185 | * r - optional vector to store the result in 186 | * 187 | * Returns: 188 | * 189 | * If r is specified, returns r after performing the operation. 190 | * Otherwise, returns a new 3-element vector with the result. 191 | */ 192 | V3.add = function V3_add(a, b, r) { 193 | //MathUtils_assert(a.length == 3, "a.length == 3"); 194 | //MathUtils_assert(b.length == 3, "b.length == 3"); 195 | //MathUtils_assert(r == undefined || r.length == 3, "r == undefined || r.length == 3"); 196 | 197 | if (r == undefined) 198 | r = new MJS_FLOAT_ARRAY_TYPE(3); 199 | r[0] = a[0] + b[0]; 200 | r[1] = a[1] + b[1]; 201 | r[2] = a[2] + b[2]; 202 | return r; 203 | }; 204 | 205 | /* 206 | * Function: V3.sub 207 | * 208 | * Perform 209 | * r = a - b. 210 | * 211 | * Parameters: 212 | * 213 | * a - the first vector operand 214 | * b - the second vector operand 215 | * r - optional vector to store the result in 216 | * 217 | * Returns: 218 | * 219 | * If r is specified, returns r after performing the operation. 220 | * Otherwise, returns a new 3-element vector with the result. 221 | */ 222 | V3.sub = function V3_sub(a, b, r) { 223 | //MathUtils_assert(a.length == 3, "a.length == 3"); 224 | //MathUtils_assert(b.length == 3, "b.length == 3"); 225 | //MathUtils_assert(r == undefined || r.length == 3, "r == undefined || r.length == 3"); 226 | 227 | if (r == undefined) 228 | r = new MJS_FLOAT_ARRAY_TYPE(3); 229 | r[0] = a[0] - b[0]; 230 | r[1] = a[1] - b[1]; 231 | r[2] = a[2] - b[2]; 232 | return r; 233 | }; 234 | 235 | /* 236 | * Function: V3.neg 237 | * 238 | * Perform 239 | * r = - a. 240 | * 241 | * Parameters: 242 | * 243 | * a - the vector operand 244 | * r - optional vector to store the result in 245 | * 246 | * Returns: 247 | * 248 | * If r is specified, returns r after performing the operation. 249 | * Otherwise, returns a new 3-element vector with the result. 250 | */ 251 | V3.neg = function V3_neg(a, r) { 252 | //MathUtils_assert(a.length == 3, "a.length == 3"); 253 | //MathUtils_assert(r == undefined || r.length == 3, "r == undefined || r.length == 3"); 254 | 255 | if (r == undefined) 256 | r = new MJS_FLOAT_ARRAY_TYPE(3); 257 | r[0] = - a[0]; 258 | r[1] = - a[1]; 259 | r[2] = - a[2]; 260 | return r; 261 | }; 262 | 263 | /* 264 | * Function: V3.direction 265 | * 266 | * Perform 267 | * r = (a - b) / |a - b|. The result is the normalized 268 | * direction from a to b. 269 | * 270 | * Parameters: 271 | * 272 | * a - the first vector operand 273 | * b - the second vector operand 274 | * r - optional vector to store the result in 275 | * 276 | * Returns: 277 | * 278 | * If r is specified, returns r after performing the operation. 279 | * Otherwise, returns a new 3-element vector with the result. 280 | */ 281 | V3.direction = function V3_direction(a, b, r) { 282 | //MathUtils_assert(a.length == 3, "a.length == 3"); 283 | //MathUtils_assert(b.length == 3, "b.length == 3"); 284 | //MathUtils_assert(r == undefined || r.length == 3, "r == undefined || r.length == 3"); 285 | 286 | if (r == undefined) 287 | r = new MJS_FLOAT_ARRAY_TYPE(3); 288 | return V3.normalize(V3.sub(a, b, r), r); 289 | }; 290 | 291 | /* 292 | * Function: V3.length 293 | * 294 | * Perform r = |a|. 295 | * 296 | * Parameters: 297 | * 298 | * a - the vector operand 299 | * 300 | * Returns: 301 | * 302 | * The length of the given vector. 303 | */ 304 | V3.length = function V3_length(a) { 305 | //MathUtils_assert(a.length == 3, "a.length == 3"); 306 | 307 | return Math.sqrt(a[0]*a[0] + a[1]*a[1] + a[2]*a[2]); 308 | }; 309 | 310 | /* 311 | * Function: V3.lengthSquard 312 | * 313 | * Perform r = |a|*|a|. 314 | * 315 | * Parameters: 316 | * 317 | * a - the vector operand 318 | * 319 | * Returns: 320 | * 321 | * The square of the length of the given vector. 322 | */ 323 | V3.lengthSquared = function V3_lengthSquared(a) { 324 | //MathUtils_assert(a.length == 3, "a.length == 3"); 325 | 326 | return a[0]*a[0] + a[1]*a[1] + a[2]*a[2]; 327 | }; 328 | 329 | V3.distance = function V3_distance(a, b) { 330 | var dx = a[0] - b[0]; 331 | var dy = a[1] - b[1]; 332 | var dz = a[2] - b[2]; 333 | return Math.sqrt(dx * dx + dy * dy + dz * dz); 334 | }; 335 | 336 | V3.distanceSquared = function V3_distanceSquared(a, b) { 337 | var dx = a[0] - b[0]; 338 | var dy = a[1] - b[1]; 339 | var dz = a[2] - b[2]; 340 | return dx * dx + dy * dy + dz * dz; 341 | }; 342 | 343 | /* 344 | * Function: V3.normalize 345 | * 346 | * Perform r = a / |a|. 347 | * 348 | * Parameters: 349 | * 350 | * a - the vector operand 351 | * r - optional vector to store the result in 352 | * 353 | * Returns: 354 | * 355 | * If r is specified, returns r after performing the operation. 356 | * Otherwise, returns a new 3-element vector with the result. 357 | */ 358 | V3.normalize = function V3_normalize(a, r) { 359 | //MathUtils_assert(a.length == 3, "a.length == 3"); 360 | //MathUtils_assert(r == undefined || r.length == 3, "r == undefined || r.length == 3"); 361 | 362 | if (r == undefined) 363 | r = new MJS_FLOAT_ARRAY_TYPE(3); 364 | var im = 1.0 / V3.length(a); 365 | r[0] = a[0] * im; 366 | r[1] = a[1] * im; 367 | r[2] = a[2] * im; 368 | return r; 369 | }; 370 | 371 | /* 372 | * Function: V3.scale 373 | * 374 | * Perform r = k * a. 375 | * 376 | * Parameters: 377 | * 378 | * a - the vector operand 379 | * k - a scalar value 380 | * r - optional vector to store the result in 381 | * 382 | * Returns: 383 | * 384 | * If r is specified, returns r after performing the operation. 385 | * Otherwise, returns a new 3-element vector with the result. 386 | */ 387 | V3.scale = function V3_scale(k, a, r) { 388 | //MathUtils_assert(a.length == 3, "a.length == 3"); 389 | //MathUtils_assert(r == undefined || r.length == 3, "r == undefined || r.length == 3"); 390 | 391 | if (r == undefined) 392 | r = new MJS_FLOAT_ARRAY_TYPE(3); 393 | r[0] = a[0] * k; 394 | r[1] = a[1] * k; 395 | r[2] = a[2] * k; 396 | return r; 397 | }; 398 | 399 | /* 400 | * Function: V3.dot 401 | * 402 | * Perform 403 | * r = dot(a, b). 404 | * 405 | * Parameters: 406 | * 407 | * a - the first vector operand 408 | * b - the second vector operand 409 | * 410 | * Returns: 411 | * 412 | * The dot product of a and b. 413 | */ 414 | V3.dot = function V3_dot(a, b) { 415 | //MathUtils_assert(a.length == 3, "a.length == 3"); 416 | //MathUtils_assert(b.length == 3, "b.length == 3"); 417 | 418 | return a[0] * b[0] + 419 | a[1] * b[1] + 420 | a[2] * b[2]; 421 | }; 422 | 423 | /* 424 | * Function: V3.cross 425 | * 426 | * Perform r = a x b. 427 | * 428 | * Parameters: 429 | * 430 | * a - the first vector operand 431 | * b - the second vector operand 432 | * r - optional vector to store the result in 433 | * 434 | * Returns: 435 | * 436 | * If r is specified, returns r after performing the operation. 437 | * Otherwise, returns a new 3-element vector with the result. 438 | */ 439 | V3.cross = function V3_cross(a, b, r) { 440 | //MathUtils_assert(a.length == 3, "a.length == 3"); 441 | //MathUtils_assert(b.length == 3, "b.length == 3"); 442 | //MathUtils_assert(r == undefined || r.length == 3, "r == undefined || r.length == 3"); 443 | 444 | if (r == undefined) 445 | r = new MJS_FLOAT_ARRAY_TYPE(3); 446 | r[0] = a[1]*b[2] - a[2]*b[1]; 447 | r[1] = a[2]*b[0] - a[0]*b[2]; 448 | r[2] = a[0]*b[1] - a[1]*b[0]; 449 | return r; 450 | }; 451 | 452 | /* 453 | * Function: V3.mul4x4 454 | * 455 | * Perform 456 | * r = m * v. 457 | * 458 | * Parameters: 459 | * 460 | * m - the 4x4 matrix operand 461 | * v - the 3-element vector operand 462 | * r - optional vector to store the result in 463 | * 464 | * Returns: 465 | * 466 | * If r is specified, returns r after performing the operation. 467 | * Otherwise, returns a new 3-element vector with the result. 468 | * The 4-element result vector is divided by the w component 469 | * and returned as a 3-element vector. 470 | */ 471 | V3.mul4x4 = function V3_mul4x4(m, v, r) { 472 | //MathUtils_assert(m.length == 16, "m.length == 16"); 473 | //MathUtils_assert(v.length == 3, "v.length == 3"); 474 | //MathUtils_assert(r == undefined || r.length == 3, "r == undefined || r.length == 3"); 475 | 476 | var w; 477 | var tmp = V3._temp1; 478 | if (r == undefined) 479 | r = new MJS_FLOAT_ARRAY_TYPE(3); 480 | tmp[0] = m[ 3]; 481 | tmp[1] = m[ 7]; 482 | tmp[2] = m[11]; 483 | w = V3.dot(v, tmp) + m[15]; 484 | tmp[0] = m[ 0]; 485 | tmp[1] = m[ 4]; 486 | tmp[2] = m[ 8]; 487 | r[0] = (V3.dot(v, tmp) + m[12])/w; 488 | tmp[0] = m[ 1]; 489 | tmp[1] = m[ 5]; 490 | tmp[2] = m[ 9]; 491 | r[1] = (V3.dot(v, tmp) + m[13])/w; 492 | tmp[0] = m[ 2]; 493 | tmp[1] = m[ 6]; 494 | tmp[2] = m[10]; 495 | r[2] = (V3.dot(v, tmp) + m[14])/w; 496 | return r; 497 | }; 498 | 499 | /* 500 | * Class: M4x4 501 | * 502 | * Methods for working with 4x4 matrices. A matrix is represented by a 16-element array 503 | * in column-major order. Any valid JavaScript array type may be used, but if new 504 | * matrices are created they are created using the configured MJS_FLOAT_ARRAY_TYPE. 505 | */ 506 | 507 | var M4x4 = { }; 508 | 509 | M4x4._temp1 = new MJS_FLOAT_ARRAY_TYPE(16); 510 | M4x4._temp2 = new MJS_FLOAT_ARRAY_TYPE(16); 511 | 512 | if (MJS_FLOAT_ARRAY_TYPE == Array) { 513 | M4x4.I = [1.0, 0.0, 0.0, 0.0, 514 | 0.0, 1.0, 0.0, 0.0, 515 | 0.0, 0.0, 1.0, 0.0, 516 | 0.0, 0.0, 0.0, 1.0]; 517 | 518 | M4x4.$ = function M4x4_$(m00, m01, m02, m03, 519 | m04, m05, m06, m07, 520 | m08, m09, m10, m11, 521 | m12, m13, m14, m15) 522 | { 523 | return [m00, m01, m02, m03, 524 | m04, m05, m06, m07, 525 | m08, m09, m10, m11, 526 | m12, m13, m14, m15]; 527 | }; 528 | } else { 529 | M4x4.I = new MJS_FLOAT_ARRAY_TYPE([1.0, 0.0, 0.0, 0.0, 530 | 0.0, 1.0, 0.0, 0.0, 531 | 0.0, 0.0, 1.0, 0.0, 532 | 0.0, 0.0, 0.0, 1.0]); 533 | 534 | /* 535 | * Function: M4x4.$ 536 | * 537 | * Creates a new 4x4 matrix with the given values. 538 | * 539 | * Parameters: 540 | * 541 | * m00..m15 - the 16 elements of the new matrix. 542 | * 543 | * Returns: 544 | * 545 | * A new matrix filled with the given argument values. 546 | */ 547 | M4x4.$ = function M4x4_$(m00, m01, m02, m03, 548 | m04, m05, m06, m07, 549 | m08, m09, m10, m11, 550 | m12, m13, m14, m15) 551 | { 552 | return new MJS_FLOAT_ARRAY_TYPE([m00, m01, m02, m03, 553 | m04, m05, m06, m07, 554 | m08, m09, m10, m11, 555 | m12, m13, m14, m15]); 556 | }; 557 | } 558 | 559 | M4x4.identity = M4x4.I; 560 | 561 | /* 562 | * Function: M4x4.fromList 563 | * 564 | * Creates a new 4x4 matrix with the given values. 565 | * 566 | * Parameters: 567 | * 568 | * list - A list of the 16 elements of the new matrix. 569 | * 570 | * Returns: 571 | * 572 | * Just a new matrix filled with the given argument values. 573 | * Nothing, if the length of the list is not exactly 16. 574 | */ 575 | M4x4.fromList = function(list) { 576 | var m = _elm_lang$core$Native_List.toArray(list); 577 | if (m.length === 16) { 578 | return _elm_lang$core$Maybe$Just(M4x4.$(m[0], m[1], m[2], m[3], m[4], m[5], m[6], m[7], m[8], m[9], m[10], m[11], m[12], m[13], m[14], m[15])); 579 | } else { 580 | return _elm_lang$core$Maybe$Nothing; 581 | } 582 | } 583 | 584 | /* 585 | * Function: M4x4.fromRecord 586 | * 587 | * Creates a new 4x4 matrix from the given record. 588 | * 589 | * Parameters: 590 | * 591 | * A record with m11..m44 attributes - the 16 elements of the new matrix 592 | * 593 | * Returns: 594 | * 595 | * A new matrix filled with the values from the given record. 596 | */ 597 | M4x4.fromRecord = function(r) { 598 | return new MJS_FLOAT_ARRAY_TYPE([ 599 | r.m11, r.m21, r.m31, r.m41, 600 | r.m12, r.m22, r.m32, r.m42, 601 | r.m13, r.m23, r.m33, r.m43, 602 | r.m14, r.m24, r.m34, r.m44 603 | ]); 604 | } 605 | 606 | /* 607 | * Function: M4x4.toRecord 608 | * 609 | * Creates a record from the given matrix 610 | * 611 | * Parameters: 612 | * 613 | * A 4x4 matrix 614 | * 615 | * Returns: 616 | * 617 | * A new record with m11..m44 attributes - the 16 elements of the given matrix 618 | */ 619 | M4x4.toRecord = function(m) { 620 | return { 621 | m11: m[0], m21: m[1], m31: m[2], m41: m[3], 622 | m12: m[4], m22: m[5], m32: m[6], m42: m[7], 623 | m13: m[8], m23: m[9], m33: m[10], m43: m[11], 624 | m14: m[12], m24: m[13], m34: m[14], m44: m[15] 625 | }; 626 | } 627 | 628 | /* 629 | * Function: M4x4.topLeft3x3 630 | * 631 | * Return the top left 3x3 matrix from the given 4x4 matrix m. 632 | * 633 | * Parameters: 634 | * 635 | * m - the matrix 636 | * r - optional 3x3 matrix to store the result in 637 | * 638 | * Returns: 639 | * 640 | * If r is specified, returns r after performing the operation. 641 | * Otherwise, returns a new 3x3 matrix with the result. 642 | */ 643 | M4x4.topLeft3x3 = function M4x4_topLeft3x3(m, r) { 644 | //MathUtils_assert(m.length == 16, "m.length == 16"); 645 | //MathUtils_assert(r == undefined || r.length == 9, "r == undefined || r.length == 9"); 646 | 647 | if (r == undefined) 648 | r = new MJS_FLOAT_ARRAY_TYPE(9); 649 | r[0] = m[0]; r[1] = m[1]; r[2] = m[2]; 650 | r[3] = m[4]; r[4] = m[5]; r[5] = m[6]; 651 | r[6] = m[8]; r[7] = m[9]; r[8] = m[10]; 652 | return r; 653 | }; 654 | 655 | /* 656 | * Function: M4x4.inverse 657 | * 658 | * Computes the inverse of the given matrix m. 659 | * 660 | * Parameters: 661 | * 662 | * m - the matrix 663 | * r - optional 4x4 matrix to store the result in 664 | * 665 | * Returns: 666 | * 667 | * If r is specified, returns r after performing the operation. 668 | * Otherwise, returns a new 4x4 matrix with the result. 669 | */ 670 | M4x4.inverse = function M4x4_inverse(m, r) { 671 | if (r == undefined) { 672 | r = new MJS_FLOAT_ARRAY_TYPE(16); 673 | } 674 | 675 | r[0] = m[5] * m[10] * m[15] - m[5] * m[11] * m[14] - m[9] * m[6] * m[15] + 676 | m[9] * m[7] * m[14] + m[13] * m[6] * m[11] - m[13] * m[7] * m[10]; 677 | r[4] = -m[4] * m[10] * m[15] + m[4] * m[11] * m[14] + m[8] * m[6] * m[15] - 678 | m[8] * m[7] * m[14] - m[12] * m[6] * m[11] + m[12] * m[7] * m[10]; 679 | r[8] = m[4] * m[9] * m[15] - m[4] * m[11] * m[13] - m[8] * m[5] * m[15] + 680 | m[8] * m[7] * m[13] + m[12] * m[5] * m[11] - m[12] * m[7] * m[9]; 681 | r[12] = -m[4] * m[9] * m[14] + m[4] * m[10] * m[13] + m[8] * m[5] * m[14] - 682 | m[8] * m[6] * m[13] - m[12] * m[5] * m[10] + m[12] * m[6] * m[9]; 683 | r[1] = -m[1] * m[10] * m[15] + m[1] * m[11] * m[14] + m[9] * m[2] * m[15] - 684 | m[9] * m[3] * m[14] - m[13] * m[2] * m[11] + m[13] * m[3] * m[10]; 685 | r[5] = m[0] * m[10] * m[15] - m[0] * m[11] * m[14] - m[8] * m[2] * m[15] + 686 | m[8] * m[3] * m[14] + m[12] * m[2] * m[11] - m[12] * m[3] * m[10]; 687 | r[9] = -m[0] * m[9] * m[15] + m[0] * m[11] * m[13] + m[8] * m[1] * m[15] - 688 | m[8] * m[3] * m[13] - m[12] * m[1] * m[11] + m[12] * m[3] * m[9]; 689 | r[13] = m[0] * m[9] * m[14] - m[0] * m[10] * m[13] - m[8] * m[1] * m[14] + 690 | m[8] * m[2] * m[13] + m[12] * m[1] * m[10] - m[12] * m[2] * m[9]; 691 | r[2] = m[1] * m[6] * m[15] - m[1] * m[7] * m[14] - m[5] * m[2] * m[15] + 692 | m[5] * m[3] * m[14] + m[13] * m[2] * m[7] - m[13] * m[3] * m[6]; 693 | r[6] = -m[0] * m[6] * m[15] + m[0] * m[7] * m[14] + m[4] * m[2] * m[15] - 694 | m[4] * m[3] * m[14] - m[12] * m[2] * m[7] + m[12] * m[3] * m[6]; 695 | r[10] = m[0] * m[5] * m[15] - m[0] * m[7] * m[13] - m[4] * m[1] * m[15] + 696 | m[4] * m[3] * m[13] + m[12] * m[1] * m[7] - m[12] * m[3] * m[5]; 697 | r[14] = -m[0] * m[5] * m[14] + m[0] * m[6] * m[13] + m[4] * m[1] * m[14] - 698 | m[4] * m[2] * m[13] - m[12] * m[1] * m[6] + m[12] * m[2] * m[5]; 699 | r[3] = -m[1] * m[6] * m[11] + m[1] * m[7] * m[10] + m[5] * m[2] * m[11] - 700 | m[5] * m[3] * m[10] - m[9] * m[2] * m[7] + m[9] * m[3] * m[6]; 701 | r[7] = m[0] * m[6] * m[11] - m[0] * m[7] * m[10] - m[4] * m[2] * m[11] + 702 | m[4] * m[3] * m[10] + m[8] * m[2] * m[7] - m[8] * m[3] * m[6]; 703 | r[11] = -m[0] * m[5] * m[11] + m[0] * m[7] * m[9] + m[4] * m[1] * m[11] - 704 | m[4] * m[3] * m[9] - m[8] * m[1] * m[7] + m[8] * m[3] * m[5]; 705 | r[15] = m[0] * m[5] * m[10] - m[0] * m[6] * m[9] - m[4] * m[1] * m[10] + 706 | m[4] * m[2] * m[9] + m[8] * m[1] * m[6] - m[8] * m[2] * m[5]; 707 | 708 | var det = m[0] * r[0] + m[1] * r[4] + m[2] * r[8] + m[3] * r[12]; 709 | 710 | if (det === 0) { 711 | return _elm_lang$core$Maybe$Nothing; 712 | } 713 | 714 | det = 1.0 / det; 715 | 716 | for (var i = 0; i < 16; i = i + 1) { 717 | r[i] = r[i] * det; 718 | } 719 | 720 | return _elm_lang$core$Maybe$Just(r); 721 | }; 722 | 723 | /* 724 | * Function: M4x4.inverseOrthonormal 725 | * 726 | * Computes the inverse of the given matrix m, assuming that 727 | * the matrix is orthonormal. 728 | * 729 | * Parameters: 730 | * 731 | * m - the matrix 732 | * r - optional 4x4 matrix to store the result in 733 | * 734 | * Returns: 735 | * 736 | * If r is specified, returns r after performing the operation. 737 | * Otherwise, returns a new 4x4 matrix with the result. 738 | */ 739 | M4x4.inverseOrthonormal = function M4x4_inverseOrthonormal(m, r) { 740 | //MathUtils_assert(m.length == 16, "m.length == 16"); 741 | //MathUtils_assert(r == undefined || r.length == 16, "r == undefined || r.length == 16"); 742 | //MathUtils_assert(m != r, "m != r"); 743 | 744 | if (r == undefined) 745 | r = new MJS_FLOAT_ARRAY_TYPE(16); 746 | M4x4.transpose(m, r); 747 | var t = [m[12], m[13], m[14]]; 748 | r[3] = r[7] = r[11] = 0; 749 | r[12] = -V3.dot([r[0], r[4], r[8]], t); 750 | r[13] = -V3.dot([r[1], r[5], r[9]], t); 751 | r[14] = -V3.dot([r[2], r[6], r[10]], t); 752 | return r; 753 | }; 754 | 755 | /* 756 | * Function: M4x4.inverseTo3x3 757 | * 758 | * Computes the inverse of the given matrix m, but calculates 759 | * only the top left 3x3 values of the result. 760 | * 761 | * Parameters: 762 | * 763 | * m - the matrix 764 | * r - optional 3x3 matrix to store the result in 765 | * 766 | * Returns: 767 | * 768 | * If r is specified, returns r after performing the operation. 769 | * Otherwise, returns a new 3x3 matrix with the result. 770 | */ 771 | M4x4.inverseTo3x3 = function M4x4_inverseTo3x3(m, r) { 772 | //MathUtils_assert(m.length == 16, "m.length == 16"); 773 | //MathUtils_assert(r == undefined || r.length == 9, "r == undefined || r.length == 9"); 774 | 775 | if (r == undefined) 776 | r = new MJS_FLOAT_ARRAY_TYPE(9); 777 | 778 | var a11 = m[10]*m[5]-m[6]*m[9], 779 | a21 = -m[10]*m[1]+m[2]*m[9], 780 | a31 = m[6]*m[1]-m[2]*m[5], 781 | a12 = -m[10]*m[4]+m[6]*m[8], 782 | a22 = m[10]*m[0]-m[2]*m[8], 783 | a32 = -m[6]*m[0]+m[2]*m[4], 784 | a13 = m[9]*m[4]-m[5]*m[8], 785 | a23 = -m[9]*m[0]+m[1]*m[8], 786 | a33 = m[5]*m[0]-m[1]*m[4]; 787 | var det = m[0]*(a11) + m[1]*(a12) + m[2]*(a13); 788 | if (det == 0) // no inverse 789 | throw "matrix not invertible"; 790 | var idet = 1.0 / det; 791 | 792 | r[0] = idet*a11; 793 | r[1] = idet*a21; 794 | r[2] = idet*a31; 795 | r[3] = idet*a12; 796 | r[4] = idet*a22; 797 | r[5] = idet*a32; 798 | r[6] = idet*a13; 799 | r[7] = idet*a23; 800 | r[8] = idet*a33; 801 | 802 | return r; 803 | }; 804 | 805 | /* 806 | * Function: M4x4.makeFrustum 807 | * 808 | * Creates a matrix for a projection frustum with the given parameters. 809 | * 810 | * Parameters: 811 | * 812 | * left - the left coordinate of the frustum 813 | * right- the right coordinate of the frustum 814 | * bottom - the bottom coordinate of the frustum 815 | * top - the top coordinate of the frustum 816 | * znear - the near z distance of the frustum 817 | * zfar - the far z distance of the frustum 818 | * r - optional 4x4 matrix to store the result in 819 | * 820 | * Returns: 821 | * 822 | * If r is specified, returns r after creating the projection matrix. 823 | * Otherwise, returns a new 4x4 matrix. 824 | */ 825 | M4x4.makeFrustum = function M4x4_makeFrustum(left, right, bottom, top, znear, zfar, r) { 826 | //MathUtils_assert(r == undefined || r.length == 16, "r == undefined || r.length == 16"); 827 | 828 | if (r == undefined) 829 | r = new MJS_FLOAT_ARRAY_TYPE(16); 830 | 831 | var X = 2*znear/(right-left); 832 | var Y = 2*znear/(top-bottom); 833 | var A = (right+left)/(right-left); 834 | var B = (top+bottom)/(top-bottom); 835 | var C = -(zfar+znear)/(zfar-znear); 836 | var D = -2*zfar*znear/(zfar-znear); 837 | 838 | r[0] = 2*znear/(right-left); 839 | r[1] = 0; 840 | r[2] = 0; 841 | r[3] = 0; 842 | r[4] = 0; 843 | r[5] = 2*znear/(top-bottom); 844 | r[6] = 0; 845 | r[7] = 0; 846 | r[8] = (right+left)/(right-left); 847 | r[9] = (top+bottom)/(top-bottom); 848 | r[10] = -(zfar+znear)/(zfar-znear); 849 | r[11] = -1; 850 | r[12] = 0; 851 | r[13] = 0; 852 | r[14] = -2*zfar*znear/(zfar-znear); 853 | r[15] = 0; 854 | 855 | return r; 856 | }; 857 | 858 | /* 859 | * Function: M4x4.makePerspective 860 | * 861 | * Creates a matrix for a perspective projection with the given parameters. 862 | * 863 | * Parameters: 864 | * 865 | * fovy - field of view in the y axis, in degrees 866 | * aspect - aspect ratio 867 | * znear - the near z distance of the projection 868 | * zfar - the far z distance of the projection 869 | * r - optional 4x4 matrix to store the result in 870 | * 871 | * Returns: 872 | * 873 | * If r is specified, returns r after creating the projection matrix. 874 | * Otherwise, returns a new 4x4 matrix. 875 | */ 876 | M4x4.makePerspective = function M4x4_makePerspective (fovy, aspect, znear, zfar, r) { 877 | //MathUtils_assert(r == undefined || r.length == 16, "r == undefined || r.length == 16"); 878 | 879 | var ymax = znear * Math.tan(fovy * Math.PI / 360.0); 880 | var ymin = -ymax; 881 | var xmin = ymin * aspect; 882 | var xmax = ymax * aspect; 883 | 884 | return M4x4.makeFrustum(xmin, xmax, ymin, ymax, znear, zfar, r); 885 | }; 886 | 887 | /* 888 | * Function: M4x4.makeOrtho 889 | * 890 | * Creates a matrix for an orthogonal frustum projection with the given parameters. 891 | * 892 | * Parameters: 893 | * 894 | * left - the left coordinate of the frustum 895 | * right- the right coordinate of the frustum 896 | * bottom - the bottom coordinate of the frustum 897 | * top - the top coordinate of the frustum 898 | * znear - the near z distance of the frustum 899 | * zfar - the far z distance of the frustum 900 | * r - optional 4x4 matrix to store the result in 901 | * 902 | * Returns: 903 | * 904 | * If r is specified, returns r after creating the projection matrix. 905 | * Otherwise, returns a new 4x4 matrix. 906 | */ 907 | M4x4.makeOrtho = function M4x4_makeOrtho (left, right, bottom, top, znear, zfar, r) { 908 | //MathUtils_assert(r == undefined || r.length == 16, "r == undefined || r.length == 16"); 909 | 910 | if (r == undefined) 911 | r = new MJS_FLOAT_ARRAY_TYPE(16); 912 | 913 | var tX = -(right+left)/(right-left); 914 | var tY = -(top+bottom)/(top-bottom); 915 | var tZ = -(zfar+znear)/(zfar-znear); 916 | var X = 2 / (right-left); 917 | var Y = 2 / (top-bottom); 918 | var Z = -2 / (zfar-znear); 919 | 920 | r[0] = 2 / (right-left); 921 | r[1] = 0; 922 | r[2] = 0; 923 | r[3] = 0; 924 | r[4] = 0; 925 | r[5] = 2 / (top-bottom); 926 | r[6] = 0; 927 | r[7] = 0; 928 | r[8] = 0; 929 | r[9] = 0; 930 | r[10] = -2 / (zfar-znear); 931 | r[11] = 0; 932 | r[12] = -(right+left)/(right-left); 933 | r[13] = -(top+bottom)/(top-bottom); 934 | r[14] = -(zfar+znear)/(zfar-znear); 935 | r[15] = 1; 936 | 937 | return r; 938 | }; 939 | 940 | /* 941 | * Function: M4x4.makeOrtho2D 942 | * 943 | * Creates a matrix for a 2D orthogonal frustum projection with the given parameters. 944 | * znear and zfar are assumed to be -1 and 1, respectively. 945 | * 946 | * Parameters: 947 | * 948 | * left - the left coordinate of the frustum 949 | * right- the right coordinate of the frustum 950 | * bottom - the bottom coordinate of the frustum 951 | * top - the top coordinate of the frustum 952 | * r - optional 4x4 matrix to store the result in 953 | * 954 | * Returns: 955 | * 956 | * If r is specified, returns r after creating the projection matrix. 957 | * Otherwise, returns a new 4x4 matrix. 958 | */ 959 | M4x4.makeOrtho2D = function M4x4_makeOrtho2D (left, right, bottom, top, r) { 960 | //MathUtils_assert(r == undefined || r.length == 16, "r == undefined || r.length == 16"); 961 | 962 | return M4x4.makeOrtho(left, right, bottom, top, -1, 1, r); 963 | }; 964 | 965 | /* 966 | * Function: M4x4.mul 967 | * 968 | * Performs r = a * b. 969 | * 970 | * Parameters: 971 | * 972 | * a - the first matrix operand 973 | * b - the second matrix operand 974 | * r - optional 4x4 matrix to store the result in 975 | * 976 | * Returns: 977 | * 978 | * If r is specified, returns r after performing the operation. 979 | * Otherwise, returns a new 4x4 matrix with the result. 980 | */ 981 | M4x4.mul = function M4x4_mul(a, b, r) { 982 | //MathUtils_assert(a.length == 16, "a.length == 16"); 983 | //MathUtils_assert(b.length == 16, "b.length == 16"); 984 | //MathUtils_assert(r == undefined || r.length == 16, "r == undefined || r.length == 16"); 985 | //MathUtils_assert(a != r && b != r, "a != r && b != r"); 986 | 987 | if (r == undefined) 988 | r = new MJS_FLOAT_ARRAY_TYPE(16); 989 | 990 | var a11 = a[0]; 991 | var a21 = a[1]; 992 | var a31 = a[2]; 993 | var a41 = a[3]; 994 | var a12 = a[4]; 995 | var a22 = a[5]; 996 | var a32 = a[6]; 997 | var a42 = a[7]; 998 | var a13 = a[8]; 999 | var a23 = a[9]; 1000 | var a33 = a[10]; 1001 | var a43 = a[11]; 1002 | var a14 = a[12]; 1003 | var a24 = a[13]; 1004 | var a34 = a[14]; 1005 | var a44 = a[15]; 1006 | 1007 | var b11 = b[0]; 1008 | var b21 = b[1]; 1009 | var b31 = b[2]; 1010 | var b41 = b[3]; 1011 | var b12 = b[4]; 1012 | var b22 = b[5]; 1013 | var b32 = b[6]; 1014 | var b42 = b[7]; 1015 | var b13 = b[8]; 1016 | var b23 = b[9]; 1017 | var b33 = b[10]; 1018 | var b43 = b[11]; 1019 | var b14 = b[12]; 1020 | var b24 = b[13]; 1021 | var b34 = b[14]; 1022 | var b44 = b[15]; 1023 | 1024 | r[0] = a11 * b11 + a12 * b21 + a13 * b31 + a14 * b41; 1025 | r[1] = a21 * b11 + a22 * b21 + a23 * b31 + a24 * b41; 1026 | r[2] = a31 * b11 + a32 * b21 + a33 * b31 + a34 * b41; 1027 | r[3] = a41 * b11 + a42 * b21 + a43 * b31 + a44 * b41; 1028 | r[4] = a11 * b12 + a12 * b22 + a13 * b32 + a14 * b42; 1029 | r[5] = a21 * b12 + a22 * b22 + a23 * b32 + a24 * b42; 1030 | r[6] = a31 * b12 + a32 * b22 + a33 * b32 + a34 * b42; 1031 | r[7] = a41 * b12 + a42 * b22 + a43 * b32 + a44 * b42; 1032 | r[8] = a11 * b13 + a12 * b23 + a13 * b33 + a14 * b43; 1033 | r[9] = a21 * b13 + a22 * b23 + a23 * b33 + a24 * b43; 1034 | r[10] = a31 * b13 + a32 * b23 + a33 * b33 + a34 * b43; 1035 | r[11] = a41 * b13 + a42 * b23 + a43 * b33 + a44 * b43; 1036 | r[12] = a11 * b14 + a12 * b24 + a13 * b34 + a14 * b44; 1037 | r[13] = a21 * b14 + a22 * b24 + a23 * b34 + a24 * b44; 1038 | r[14] = a31 * b14 + a32 * b24 + a33 * b34 + a34 * b44; 1039 | r[15] = a41 * b14 + a42 * b24 + a43 * b34 + a44 * b44; 1040 | 1041 | return r; 1042 | }; 1043 | 1044 | /* 1045 | * Function: M4x4.mulAffine 1046 | * 1047 | * Performs r = a * b, assuming a and b are affine (elements 3,7,11,15 = 0,0,0,1) 1048 | * 1049 | * Parameters: 1050 | * 1051 | * a - the first matrix operand 1052 | * b - the second matrix operand 1053 | * r - optional 4x4 matrix to store the result in 1054 | * 1055 | * Returns: 1056 | * 1057 | * If r is specified, returns r after performing the operation. 1058 | * Otherwise, returns a new 4x4 matrix with the result. 1059 | */ 1060 | M4x4.mulAffine = function M4x4_mulAffine(a, b, r) { 1061 | //MathUtils_assert(a.length == 16, "a.length == 16"); 1062 | //MathUtils_assert(b.length == 16, "b.length == 16"); 1063 | //MathUtils_assert(r == undefined || r.length == 16, "r == undefined || r.length == 16"); 1064 | //MathUtils_assert(a != r && b != r, "a != r && b != r"); 1065 | 1066 | if (r == undefined) 1067 | r = new MJS_FLOAT_ARRAY_TYPE(16); 1068 | var a11 = a[0]; 1069 | var a21 = a[1]; 1070 | var a31 = a[2]; 1071 | var a12 = a[4]; 1072 | var a22 = a[5]; 1073 | var a32 = a[6]; 1074 | var a13 = a[8]; 1075 | var a23 = a[9]; 1076 | var a33 = a[10]; 1077 | var a14 = a[12]; 1078 | var a24 = a[13]; 1079 | var a34 = a[14]; 1080 | 1081 | var b11 = b[0]; 1082 | var b21 = b[1]; 1083 | var b31 = b[2]; 1084 | var b12 = b[4]; 1085 | var b22 = b[5]; 1086 | var b32 = b[6]; 1087 | var b13 = b[8]; 1088 | var b23 = b[9]; 1089 | var b33 = b[10]; 1090 | var b14 = b[12]; 1091 | var b24 = b[13]; 1092 | var b34 = b[14]; 1093 | 1094 | r[0] = a11 * b11 + a12 * b21 + a13 * b31; 1095 | r[1] = a21 * b11 + a22 * b21 + a23 * b31; 1096 | r[2] = a31 * b11 + a32 * b21 + a33 * b31; 1097 | r[3] = 0; 1098 | r[4] = a11 * b12 + a12 * b22 + a13 * b32; 1099 | r[5] = a21 * b12 + a22 * b22 + a23 * b32; 1100 | r[6] = a31 * b12 + a32 * b22 + a33 * b32; 1101 | r[7] = 0; 1102 | r[8] = a11 * b13 + a12 * b23 + a13 * b33; 1103 | r[9] = a21 * b13 + a22 * b23 + a23 * b33; 1104 | r[10] = a31 * b13 + a32 * b23 + a33 * b33; 1105 | r[11] = 0; 1106 | r[12] = a11 * b14 + a12 * b24 + a13 * b34 + a14; 1107 | r[13] = a21 * b14 + a22 * b24 + a23 * b34 + a24; 1108 | r[14] = a31 * b14 + a32 * b24 + a33 * b34 + a34; 1109 | r[15] = 1; 1110 | 1111 | return r; 1112 | }; 1113 | 1114 | /* 1115 | * Function: M4x4.makeRotate 1116 | * 1117 | * Creates a transformation matrix for rotation by angle radians about the 3-element vector axis. 1118 | * 1119 | * Parameters: 1120 | * 1121 | * angle - the angle of rotation, in radians 1122 | * axis - the axis around which the rotation is performed, a 3-element vector 1123 | * r - optional 4x4 matrix to store the result in 1124 | * 1125 | * Returns: 1126 | * 1127 | * If r is specified, returns r after creating the matrix. 1128 | * Otherwise, returns a new 4x4 matrix with the result. 1129 | */ 1130 | M4x4.makeRotate = function M4x4_makeRotate(angle, axis, r) { 1131 | //MathUtils_assert(angle.length == 3, "angle.length == 3"); 1132 | //MathUtils_assert(axis.length == 3, "axis.length == 3"); 1133 | //MathUtils_assert(r == undefined || r.length == 16, "r == undefined || r.length == 16"); 1134 | 1135 | if (r == undefined) 1136 | r = new MJS_FLOAT_ARRAY_TYPE(16); 1137 | 1138 | axis = V3.normalize(axis, V3._temp1); 1139 | var x = axis[0], y = axis[1], z = axis[2]; 1140 | var c = Math.cos(angle); 1141 | var c1 = 1-c; 1142 | var s = Math.sin(angle); 1143 | 1144 | r[0] = x*x*c1+c; 1145 | r[1] = y*x*c1+z*s; 1146 | r[2] = z*x*c1-y*s; 1147 | r[3] = 0; 1148 | r[4] = x*y*c1-z*s; 1149 | r[5] = y*y*c1+c; 1150 | r[6] = y*z*c1+x*s; 1151 | r[7] = 0; 1152 | r[8] = x*z*c1+y*s; 1153 | r[9] = y*z*c1-x*s; 1154 | r[10] = z*z*c1+c; 1155 | r[11] = 0; 1156 | r[12] = 0; 1157 | r[13] = 0; 1158 | r[14] = 0; 1159 | r[15] = 1; 1160 | 1161 | return r; 1162 | }; 1163 | 1164 | /* 1165 | * Function: M4x4.rotate 1166 | * 1167 | * Concatenates a rotation of angle radians about the axis to the give matrix m. 1168 | * 1169 | * Parameters: 1170 | * 1171 | * angle - the angle of rotation, in radians 1172 | * axis - the axis around which the rotation is performed, a 3-element vector 1173 | * m - the matrix to concatenate the rotation to 1174 | * r - optional 4x4 matrix to store the result in 1175 | * 1176 | * Returns: 1177 | * 1178 | * If r is specified, returns r after performing the operation. 1179 | * Otherwise, returns a new 4x4 matrix with the result. 1180 | */ 1181 | M4x4.rotate = function M4x4_rotate(angle, axis, m, r) { 1182 | //MathUtils_assert(angle.length == 3, "angle.length == 3"); 1183 | //MathUtils_assert(axis.length == 3, "axis.length == 3"); 1184 | //MathUtils_assert(m.length == 16, "m.length == 16"); 1185 | //MathUtils_assert(r == undefined || r.length == 16, "r == undefined || r.length == 16"); 1186 | 1187 | if (r == undefined) 1188 | r = new MJS_FLOAT_ARRAY_TYPE(16); 1189 | var a0=axis [0], a1=axis [1], a2=axis [2]; 1190 | var l = Math.sqrt(a0*a0 + a1*a1 + a2*a2); 1191 | var x = a0, y = a1, z = a2; 1192 | if (l != 1.0) { 1193 | var im = 1.0 / l; 1194 | x *= im; 1195 | y *= im; 1196 | z *= im; 1197 | } 1198 | var c = Math.cos(angle); 1199 | var c1 = 1-c; 1200 | var s = Math.sin(angle); 1201 | var xs = x*s; 1202 | var ys = y*s; 1203 | var zs = z*s; 1204 | var xyc1 = x * y * c1; 1205 | var xzc1 = x * z * c1; 1206 | var yzc1 = y * z * c1; 1207 | 1208 | var m11 = m[0]; 1209 | var m21 = m[1]; 1210 | var m31 = m[2]; 1211 | var m41 = m[3]; 1212 | var m12 = m[4]; 1213 | var m22 = m[5]; 1214 | var m32 = m[6]; 1215 | var m42 = m[7]; 1216 | var m13 = m[8]; 1217 | var m23 = m[9]; 1218 | var m33 = m[10]; 1219 | var m43 = m[11]; 1220 | 1221 | var t11 = x * x * c1 + c; 1222 | var t21 = xyc1 + zs; 1223 | var t31 = xzc1 - ys; 1224 | var t12 = xyc1 - zs; 1225 | var t22 = y * y * c1 + c; 1226 | var t32 = yzc1 + xs; 1227 | var t13 = xzc1 + ys; 1228 | var t23 = yzc1 - xs; 1229 | var t33 = z * z * c1 + c; 1230 | 1231 | r[0] = m11 * t11 + m12 * t21 + m13 * t31; 1232 | r[1] = m21 * t11 + m22 * t21 + m23 * t31; 1233 | r[2] = m31 * t11 + m32 * t21 + m33 * t31; 1234 | r[3] = m41 * t11 + m42 * t21 + m43 * t31; 1235 | r[4] = m11 * t12 + m12 * t22 + m13 * t32; 1236 | r[5] = m21 * t12 + m22 * t22 + m23 * t32; 1237 | r[6] = m31 * t12 + m32 * t22 + m33 * t32; 1238 | r[7] = m41 * t12 + m42 * t22 + m43 * t32; 1239 | r[8] = m11 * t13 + m12 * t23 + m13 * t33; 1240 | r[9] = m21 * t13 + m22 * t23 + m23 * t33; 1241 | r[10] = m31 * t13 + m32 * t23 + m33 * t33; 1242 | r[11] = m41 * t13 + m42 * t23 + m43 * t33; 1243 | if (r != m) { 1244 | r[12] = m[12]; 1245 | r[13] = m[13]; 1246 | r[14] = m[14]; 1247 | r[15] = m[15]; 1248 | } 1249 | return r; 1250 | }; 1251 | 1252 | /* 1253 | * Function: M4x4.makeScale3 1254 | * 1255 | * Creates a transformation matrix for scaling by 3 scalar values, one for 1256 | * each of the x, y, and z directions. 1257 | * 1258 | * Parameters: 1259 | * 1260 | * x - the scale for the x axis 1261 | * y - the scale for the y axis 1262 | * z - the scale for the z axis 1263 | * r - optional 4x4 matrix to store the result in 1264 | * 1265 | * Returns: 1266 | * 1267 | * If r is specified, returns r after creating the matrix. 1268 | * Otherwise, returns a new 4x4 matrix with the result. 1269 | */ 1270 | M4x4.makeScale3 = function M4x4_makeScale3(x, y, z, r) { 1271 | //MathUtils_assert(r == undefined || r.length == 16, "r == undefined || r.length == 16"); 1272 | 1273 | if (r == undefined) 1274 | r = new MJS_FLOAT_ARRAY_TYPE(16); 1275 | 1276 | r[0] = x; 1277 | r[1] = 0; 1278 | r[2] = 0; 1279 | r[3] = 0; 1280 | r[4] = 0; 1281 | r[5] = y; 1282 | r[6] = 0; 1283 | r[7] = 0; 1284 | r[8] = 0; 1285 | r[9] = 0; 1286 | r[10] = z; 1287 | r[11] = 0; 1288 | r[12] = 0; 1289 | r[13] = 0; 1290 | r[14] = 0; 1291 | r[15] = 1; 1292 | 1293 | return r; 1294 | }; 1295 | 1296 | /* 1297 | * Function: M4x4.makeScale1 1298 | * 1299 | * Creates a transformation matrix for a uniform scale by a single scalar value. 1300 | * 1301 | * Parameters: 1302 | * 1303 | * k - the scale factor 1304 | * r - optional 4x4 matrix to store the result in 1305 | * 1306 | * Returns: 1307 | * 1308 | * If r is specified, returns r after creating the matrix. 1309 | * Otherwise, returns a new 4x4 matrix with the result. 1310 | */ 1311 | M4x4.makeScale1 = function M4x4_makeScale1(k, r) { 1312 | //MathUtils_assert(r == undefined || r.length == 16, "r == undefined || r.length == 16"); 1313 | 1314 | return M4x4.makeScale3(k, k, k, r); 1315 | }; 1316 | 1317 | /* 1318 | * Function: M4x4.makeScale 1319 | * 1320 | * Creates a transformation matrix for scaling each of the x, y, and z axes by the amount 1321 | * given in the corresponding element of the 3-element vector. 1322 | * 1323 | * Parameters: 1324 | * 1325 | * v - the 3-element vector containing the scale factors 1326 | * r - optional 4x4 matrix to store the result in 1327 | * 1328 | * Returns: 1329 | * 1330 | * If r is specified, returns r after creating the matrix. 1331 | * Otherwise, returns a new 4x4 matrix with the result. 1332 | */ 1333 | M4x4.makeScale = function M4x4_makeScale(v, r) { 1334 | //MathUtils_assert(v.length == 3, "v.length == 3"); 1335 | //MathUtils_assert(r == undefined || r.length == 16, "r == undefined || r.length == 16"); 1336 | 1337 | return M4x4.makeScale3(v[0], v[1], v[2], r); 1338 | }; 1339 | 1340 | /* 1341 | * Function: M4x4.scale3 1342 | */ 1343 | M4x4.scale3 = function M4x4_scale3(x, y, z, m, r) { 1344 | //MathUtils_assert(m.length == 16, "m.length == 16"); 1345 | //MathUtils_assert(r == undefined || r.length == 16, "r == undefined || r.length == 16"); 1346 | 1347 | if (r == m) { 1348 | m[0] *= x; 1349 | m[1] *= x; 1350 | m[2] *= x; 1351 | m[3] *= x; 1352 | m[4] *= y; 1353 | m[5] *= y; 1354 | m[6] *= y; 1355 | m[7] *= y; 1356 | m[8] *= z; 1357 | m[9] *= z; 1358 | m[10] *= z; 1359 | m[11] *= z; 1360 | return m; 1361 | } 1362 | 1363 | if (r == undefined) 1364 | r = new MJS_FLOAT_ARRAY_TYPE(16); 1365 | 1366 | r[0] = m[0] * x; 1367 | r[1] = m[1] * x; 1368 | r[2] = m[2] * x; 1369 | r[3] = m[3] * x; 1370 | r[4] = m[4] * y; 1371 | r[5] = m[5] * y; 1372 | r[6] = m[6] * y; 1373 | r[7] = m[7] * y; 1374 | r[8] = m[8] * z; 1375 | r[9] = m[9] * z; 1376 | r[10] = m[10] * z; 1377 | r[11] = m[11] * z; 1378 | r[12] = m[12]; 1379 | r[13] = m[13]; 1380 | r[14] = m[14]; 1381 | r[15] = m[15]; 1382 | 1383 | return r; 1384 | }; 1385 | 1386 | /* 1387 | * Function: M4x4.scale1 1388 | */ 1389 | M4x4.scale1 = function M4x4_scale1(k, m, r) { 1390 | //MathUtils_assert(m.length == 16, "m.length == 16"); 1391 | //MathUtils_assert(r == undefined || r.length == 16, "r == undefined || r.length == 16"); 1392 | if (r == m) { 1393 | m[0] *= k; 1394 | m[1] *= k; 1395 | m[2] *= k; 1396 | m[3] *= k; 1397 | m[4] *= k; 1398 | m[5] *= k; 1399 | m[6] *= k; 1400 | m[7] *= k; 1401 | m[8] *= k; 1402 | m[9] *= k; 1403 | m[10] *= k; 1404 | m[11] *= k; 1405 | return m; 1406 | } 1407 | 1408 | 1409 | if (r == undefined) 1410 | r = new MJS_FLOAT_ARRAY_TYPE(16); 1411 | 1412 | r[0] = m[0] * k; 1413 | r[1] = m[1] * k; 1414 | r[2] = m[2] * k; 1415 | r[3] = m[3] * k; 1416 | r[4] = m[4] * k; 1417 | r[5] = m[5] * k; 1418 | r[6] = m[6] * k; 1419 | r[7] = m[7] * k; 1420 | r[8] = m[8] * k; 1421 | r[9] = m[9] * k; 1422 | r[10] = m[10] * k; 1423 | r[11] = m[11] * k; 1424 | r[12] = m[12]; 1425 | r[13] = m[13]; 1426 | r[14] = m[14]; 1427 | r[15] = m[15]; 1428 | 1429 | return r; 1430 | }; 1431 | 1432 | /* 1433 | * Function: M4x4.scale1 1434 | */ 1435 | M4x4.scale = function M4x4_scale(v, m, r) { 1436 | //MathUtils_assert(v.length == 3, "v.length == 3"); 1437 | //MathUtils_assert(m.length == 16, "m.length == 16"); 1438 | //MathUtils_assert(r == undefined || r.length == 16, "r == undefined || r.length == 16"); 1439 | var x = v[0], y = v[1], z = v[2]; 1440 | 1441 | if (r == m) { 1442 | m[0] *= x; 1443 | m[1] *= x; 1444 | m[2] *= x; 1445 | m[3] *= x; 1446 | m[4] *= y; 1447 | m[5] *= y; 1448 | m[6] *= y; 1449 | m[7] *= y; 1450 | m[8] *= z; 1451 | m[9] *= z; 1452 | m[10] *= z; 1453 | m[11] *= z; 1454 | return m; 1455 | } 1456 | 1457 | if (r == undefined) 1458 | r = new MJS_FLOAT_ARRAY_TYPE(16); 1459 | 1460 | 1461 | r[0] = m[0] * x; 1462 | r[1] = m[1] * x; 1463 | r[2] = m[2] * x; 1464 | r[3] = m[3] * x; 1465 | r[4] = m[4] * y; 1466 | r[5] = m[5] * y; 1467 | r[6] = m[6] * y; 1468 | r[7] = m[7] * y; 1469 | r[8] = m[8] * z; 1470 | r[9] = m[9] * z; 1471 | r[10] = m[10] * z; 1472 | r[11] = m[11] * z; 1473 | r[12] = m[12]; 1474 | r[13] = m[13]; 1475 | r[14] = m[14]; 1476 | r[15] = m[15]; 1477 | 1478 | return r; 1479 | }; 1480 | 1481 | /* 1482 | * Function: M4x4.makeTranslate3 1483 | */ 1484 | M4x4.makeTranslate3 = function M4x4_makeTranslate3(x, y, z, r) { 1485 | //MathUtils_assert(r == undefined || r.length == 16, "r == undefined || r.length == 16"); 1486 | 1487 | if (r == undefined) 1488 | r = new MJS_FLOAT_ARRAY_TYPE(16); 1489 | 1490 | r[0] = 1; 1491 | r[1] = 0; 1492 | r[2] = 0; 1493 | r[3] = 0; 1494 | r[4] = 0; 1495 | r[5] = 1; 1496 | r[6] = 0; 1497 | r[7] = 0; 1498 | r[8] = 0; 1499 | r[9] = 0; 1500 | r[10] = 1; 1501 | r[11] = 0; 1502 | r[12] = x; 1503 | r[13] = y; 1504 | r[14] = z; 1505 | r[15] = 1; 1506 | 1507 | return r; 1508 | }; 1509 | 1510 | /* 1511 | * Function: M4x4.makeTranslate1 1512 | */ 1513 | M4x4.makeTranslate1 = function M4x4_makeTranslate1 (k, r) { 1514 | //MathUtils_assert(r == undefined || r.length == 16, "r == undefined || r.length == 16"); 1515 | 1516 | return M4x4.makeTranslate3(k, k, k, r); 1517 | }; 1518 | 1519 | /* 1520 | * Function: M4x4.makeTranslate 1521 | */ 1522 | M4x4.makeTranslate = function M4x4_makeTranslate (v, r) { 1523 | //MathUtils_assert(v.length == 3, "v.length == 3"); 1524 | //MathUtils_assert(r == undefined || r.length == 16, "r == undefined || r.length == 16"); 1525 | 1526 | return M4x4.makeTranslate3(v[0], v[1], v[2], r); 1527 | }; 1528 | 1529 | /* 1530 | * Function: M4x4.translate3Self 1531 | */ 1532 | M4x4.translate3Self = function M4x4_translate3Self (x, y, z, m) { 1533 | //MathUtils_assert(m.length == 16, "m.length == 16"); 1534 | //MathUtils_assert(r == undefined || r.length == 16, "r == undefined || r.length == 16"); 1535 | m[12] += m[0] * x + m[4] * y + m[8] * z; 1536 | m[13] += m[1] * x + m[5] * y + m[9] * z; 1537 | m[14] += m[2] * x + m[6] * y + m[10] * z; 1538 | m[15] += m[3] * x + m[7] * y + m[11] * z; 1539 | return m; 1540 | }; 1541 | 1542 | /* 1543 | * Function: M4x4.translate3 1544 | */ 1545 | M4x4.translate3 = function M4x4_translate3 (x, y, z, m, r) { 1546 | //MathUtils_assert(m.length == 16, "m.length == 16"); 1547 | //MathUtils_assert(r == undefined || r.length == 16, "r == undefined || r.length == 16"); 1548 | 1549 | if (r == m) { 1550 | m[12] += m[0] * x + m[4] * y + m[8] * z; 1551 | m[13] += m[1] * x + m[5] * y + m[9] * z; 1552 | m[14] += m[2] * x + m[6] * y + m[10] * z; 1553 | m[15] += m[3] * x + m[7] * y + m[11] * z; 1554 | return m; 1555 | } 1556 | 1557 | if (r == undefined) 1558 | r = new MJS_FLOAT_ARRAY_TYPE(16); 1559 | 1560 | var m11 = m[0]; 1561 | var m21 = m[1]; 1562 | var m31 = m[2]; 1563 | var m41 = m[3]; 1564 | var m12 = m[4]; 1565 | var m22 = m[5]; 1566 | var m32 = m[6]; 1567 | var m42 = m[7]; 1568 | var m13 = m[8]; 1569 | var m23 = m[9]; 1570 | var m33 = m[10]; 1571 | var m43 = m[11]; 1572 | 1573 | 1574 | r[0] = m11; 1575 | r[1] = m21; 1576 | r[2] = m31; 1577 | r[3] = m41; 1578 | r[4] = m12; 1579 | r[5] = m22; 1580 | r[6] = m32; 1581 | r[7] = m42; 1582 | r[8] = m13; 1583 | r[9] = m23; 1584 | r[10] = m33; 1585 | r[11] = m43; 1586 | r[12] = m11 * x + m12 * y + m13 * z + m[12]; 1587 | r[13] = m21 * x + m22 * y + m23 * z + m[13]; 1588 | r[14] = m31 * x + m32 * y + m33 * z + m[14]; 1589 | r[15] = m41 * x + m42 * y + m43 * z + m[15]; 1590 | 1591 | return r; 1592 | }; 1593 | 1594 | /* 1595 | * Function: M4x4.translate1 1596 | */ 1597 | M4x4.translate1 = function M4x4_translate1 (k, m, r) { 1598 | //MathUtils_assert(m.length == 16, "m.length == 16"); 1599 | //MathUtils_assert(r == undefined || r.length == 16, "r == undefined || r.length == 16"); 1600 | 1601 | return M4x4.translate3(k, k, k, m, r); 1602 | }; 1603 | /* 1604 | * Function: M4x4.translateSelf 1605 | */ 1606 | M4x4.translateSelf = function M4x4_translateSelf (v, m) { 1607 | //MathUtils_assert(v.length == 3, "v.length == 3"); 1608 | //MathUtils_assert(m.length == 16, "m.length == 16"); 1609 | var x=v[0], y=v[1], z=v[2]; 1610 | m[12] += m[0] * x + m[4] * y + m[8] * z; 1611 | m[13] += m[1] * x + m[5] * y + m[9] * z; 1612 | m[14] += m[2] * x + m[6] * y + m[10] * z; 1613 | m[15] += m[3] * x + m[7] * y + m[11] * z; 1614 | return m; 1615 | }; 1616 | /* 1617 | * Function: M4x4.translate 1618 | */ 1619 | M4x4.translate = function M4x4_translate (v, m, r) { 1620 | //MathUtils_assert(v.length == 3, "v.length == 3"); 1621 | //MathUtils_assert(m.length == 16, "m.length == 16"); 1622 | //MathUtils_assert(r == undefined || r.length == 16, "r == undefined || r.length == 16"); 1623 | var x=v[0], y=v[1], z=v[2]; 1624 | if (r == m) { 1625 | m[12] += m[0] * x + m[4] * y + m[8] * z; 1626 | m[13] += m[1] * x + m[5] * y + m[9] * z; 1627 | m[14] += m[2] * x + m[6] * y + m[10] * z; 1628 | m[15] += m[3] * x + m[7] * y + m[11] * z; 1629 | return m; 1630 | } 1631 | 1632 | if (r == undefined) 1633 | r = new MJS_FLOAT_ARRAY_TYPE(16); 1634 | 1635 | var m11 = m[0]; 1636 | var m21 = m[1]; 1637 | var m31 = m[2]; 1638 | var m41 = m[3]; 1639 | var m12 = m[4]; 1640 | var m22 = m[5]; 1641 | var m32 = m[6]; 1642 | var m42 = m[7]; 1643 | var m13 = m[8]; 1644 | var m23 = m[9]; 1645 | var m33 = m[10]; 1646 | var m43 = m[11]; 1647 | 1648 | r[0] = m11; 1649 | r[1] = m21; 1650 | r[2] = m31; 1651 | r[3] = m41; 1652 | r[4] = m12; 1653 | r[5] = m22; 1654 | r[6] = m32; 1655 | r[7] = m42; 1656 | r[8] = m13; 1657 | r[9] = m23; 1658 | r[10] = m33; 1659 | r[11] = m43; 1660 | r[12] = m11 * x + m12 * y + m13 * z + m[12]; 1661 | r[13] = m21 * x + m22 * y + m23 * z + m[13]; 1662 | r[14] = m31 * x + m32 * y + m33 * z + m[14]; 1663 | r[15] = m41 * x + m42 * y + m43 * z + m[15]; 1664 | 1665 | return r; 1666 | }; 1667 | 1668 | /* 1669 | * Function: M4x4.makeLookAt 1670 | */ 1671 | M4x4.makeLookAt = function M4x4_makeLookAt (eye, center, up, r) { 1672 | //MathUtils_assert(eye.length == 3, "eye.length == 3"); 1673 | //MathUtils_assert(center.length == 3, "center.length == 3"); 1674 | //MathUtils_assert(up.length == 3, "up.length == 3"); 1675 | //MathUtils_assert(r == undefined || r.length == 16, "r == undefined || r.length == 16"); 1676 | 1677 | var z = V3.direction(eye, center, V3._temp1); 1678 | var x = V3.normalize(V3.cross(up, z, V3._temp2), V3._temp2); 1679 | var y = V3.normalize(V3.cross(z, x, V3._temp3), V3._temp3); 1680 | 1681 | var tm1 = M4x4._temp1; 1682 | var tm2 = M4x4._temp2; 1683 | 1684 | tm1[0] = x[0]; 1685 | tm1[1] = y[0]; 1686 | tm1[2] = z[0]; 1687 | tm1[3] = 0; 1688 | tm1[4] = x[1]; 1689 | tm1[5] = y[1]; 1690 | tm1[6] = z[1]; 1691 | tm1[7] = 0; 1692 | tm1[8] = x[2]; 1693 | tm1[9] = y[2]; 1694 | tm1[10] = z[2]; 1695 | tm1[11] = 0; 1696 | tm1[12] = 0; 1697 | tm1[13] = 0; 1698 | tm1[14] = 0; 1699 | tm1[15] = 1; 1700 | 1701 | tm2[0] = 1; tm2[1] = 0; tm2[2] = 0; tm2[3] = 0; 1702 | tm2[4] = 0; tm2[5] = 1; tm2[6] = 0; tm2[7] = 0; 1703 | tm2[8] = 0; tm2[9] = 0; tm2[10] = 1; tm2[11] = 0; 1704 | tm2[12] = -eye[0]; tm2[13] = -eye[1]; tm2[14] = -eye[2]; tm2[15] = 1; 1705 | 1706 | if (r == undefined) 1707 | r = new MJS_FLOAT_ARRAY_TYPE(16); 1708 | return M4x4.mul(tm1, tm2, r); 1709 | }; 1710 | 1711 | /* 1712 | * Function: M4x4.transposeSelf 1713 | */ 1714 | M4x4.transposeSelf = function M4x4_transposeSelf (m) { 1715 | //MathUtils_assert(m.length == 16, "m.length == 16"); 1716 | var tmp = m[1]; m[1] = m[4]; m[4] = tmp; 1717 | tmp = m[2]; m[2] = m[8]; m[8] = tmp; 1718 | tmp = m[3]; m[3] = m[12]; m[12] = tmp; 1719 | tmp = m[6]; m[6] = m[9]; m[9] = tmp; 1720 | tmp = m[7]; m[7] = m[13]; m[13] = tmp; 1721 | tmp = m[11]; m[11] = m[14]; m[14] = tmp; 1722 | return m; 1723 | }; 1724 | /* 1725 | * Function: M4x4.transpose 1726 | */ 1727 | M4x4.transpose = function M4x4_transpose (m, r) { 1728 | //MathUtils_assert(m.length == 16, "m.length == 16"); 1729 | //MathUtils_assert(r == undefined || r.length == 16, "r == undefined || r.length == 16"); 1730 | 1731 | if (m == r) { 1732 | var tmp = 0.0; 1733 | tmp = m[1]; m[1] = m[4]; m[4] = tmp; 1734 | tmp = m[2]; m[2] = m[8]; m[8] = tmp; 1735 | tmp = m[3]; m[3] = m[12]; m[12] = tmp; 1736 | tmp = m[6]; m[6] = m[9]; m[9] = tmp; 1737 | tmp = m[7]; m[7] = m[13]; m[13] = tmp; 1738 | tmp = m[11]; m[11] = m[14]; m[14] = tmp; 1739 | return m; 1740 | } 1741 | 1742 | if (r == undefined) 1743 | r = new MJS_FLOAT_ARRAY_TYPE(16); 1744 | 1745 | r[0] = m[0]; r[1] = m[4]; r[2] = m[8]; r[3] = m[12]; 1746 | r[4] = m[1]; r[5] = m[5]; r[6] = m[9]; r[7] = m[13]; 1747 | r[8] = m[2]; r[9] = m[6]; r[10] = m[10]; r[11] = m[14]; 1748 | r[12] = m[3]; r[13] = m[7]; r[14] = m[11]; r[15] = m[15]; 1749 | 1750 | return r; 1751 | }; 1752 | 1753 | 1754 | /* 1755 | * Function: M4x4.transformPoint 1756 | */ 1757 | M4x4.transformPoint = function M4x4_transformPoint (m, v, r) { 1758 | //MathUtils_assert(m.length == 16, "m.length == 16"); 1759 | //MathUtils_assert(v.length == 3, "v.length == 3"); 1760 | //MathUtils_assert(r == undefined || r.length == 3, "r == undefined || r.length == 3"); 1761 | if (r == undefined) 1762 | r = new MJS_FLOAT_ARRAY_TYPE(3); 1763 | 1764 | var v0 = v[0], v1 = v[1], v2 = v[2]; 1765 | 1766 | r[0] = m[0] * v0 + m[4] * v1 + m[8] * v2 + m[12]; 1767 | r[1] = m[1] * v0 + m[5] * v1 + m[9] * v2 + m[13]; 1768 | r[2] = m[2] * v0 + m[6] * v1 + m[10] * v2 + m[14]; 1769 | var w = m[3] * v0 + m[7] * v1 + m[11] * v2 + m[15]; 1770 | 1771 | if (w != 1.0) { 1772 | r[0] /= w; 1773 | r[1] /= w; 1774 | r[2] /= w; 1775 | } 1776 | 1777 | return r; 1778 | }; 1779 | 1780 | /* 1781 | * Function: M4x4.transformLine 1782 | */ 1783 | M4x4.transformLine = function M4x4_transformLine(m, v, r) { 1784 | //MathUtils_assert(m.length == 16, "m.length == 16"); 1785 | //MathUtils_assert(v.length == 3, "v.length == 3"); 1786 | //MathUtils_assert(r == undefined || r.length == 3, "r == undefined || r.length == 3"); 1787 | if (r == undefined) 1788 | r = new MJS_FLOAT_ARRAY_TYPE(3); 1789 | 1790 | var v0 = v[0], v1 = v[1], v2 = v[2]; 1791 | r[0] = m[0] * v0 + m[4] * v1 + m[8] * v2; 1792 | r[1] = m[1] * v0 + m[5] * v1 + m[9] * v2; 1793 | r[2] = m[2] * v0 + m[6] * v1 + m[10] * v2; 1794 | var w = m[3] * v0 + m[7] * v1 + m[11] * v2; 1795 | 1796 | if (w != 1.0) { 1797 | r[0] /= w; 1798 | r[1] /= w; 1799 | r[2] /= w; 1800 | } 1801 | 1802 | return r; 1803 | }; 1804 | 1805 | 1806 | /* 1807 | * Function: M4x4.transformPointAffine 1808 | */ 1809 | M4x4.transformPointAffine = function M4x4_transformPointAffine (m, v, r) { 1810 | //MathUtils_assert(m.length == 16, "m.length == 16"); 1811 | //MathUtils_assert(v.length == 3, "v.length == 3"); 1812 | //MathUtils_assert(r == undefined || r.length == 3, "r == undefined || r.length == 3"); 1813 | if (r == undefined) 1814 | r = new MJS_FLOAT_ARRAY_TYPE(3); 1815 | 1816 | var v0 = v[0], v1 = v[1], v2 = v[2]; 1817 | 1818 | r[0] = m[0] * v0 + m[4] * v1 + m[8] * v2 + m[12]; 1819 | r[1] = m[1] * v0 + m[5] * v1 + m[9] * v2 + m[13]; 1820 | r[2] = m[2] * v0 + m[6] * v1 + m[10] * v2 + m[14]; 1821 | 1822 | return r; 1823 | }; 1824 | 1825 | /* 1826 | * Function: M4x4.transformLineAffine 1827 | */ 1828 | M4x4.transformLineAffine = function M4x4_transformLineAffine(m, v, r) { 1829 | //MathUtils_assert(m.length == 16, "m.length == 16"); 1830 | //MathUtils_assert(v.length == 3, "v.length == 3"); 1831 | //MathUtils_assert(r == undefined || r.length == 3, "r == undefined || r.length == 3"); 1832 | if (r == undefined) 1833 | r = new MJS_FLOAT_ARRAY_TYPE(3); 1834 | 1835 | var v0 = v[0], v1 = v[1], v2 = v[2]; 1836 | r[0] = m[0] * v0 + m[4] * v1 + m[8] * v2; 1837 | r[1] = m[1] * v0 + m[5] * v1 + m[9] * v2; 1838 | r[2] = m[2] * v0 + m[6] * v1 + m[10] * v2; 1839 | 1840 | return r; 1841 | }; 1842 | 1843 | M4x4.makeBasis = function M4x4_makeBasis(vx,vy,vz) { 1844 | 1845 | var r = new MJS_FLOAT_ARRAY_TYPE(16); 1846 | 1847 | r[0] = vx[0]; 1848 | r[1] = vx[1]; 1849 | r[2] = vx[2]; 1850 | r[3] = 0; 1851 | r[4] = vy[0]; 1852 | r[5] = vy[1]; 1853 | r[6] = vy[2]; 1854 | r[7] = 0; 1855 | r[8] = vz[0]; 1856 | r[9] = vz[1]; 1857 | r[10] = vz[2]; 1858 | r[11] = 0; 1859 | r[12] = 0; 1860 | r[13] = 0; 1861 | r[14] = 0; 1862 | r[15] = 1; 1863 | 1864 | return r; 1865 | 1866 | }; 1867 | 1868 | return { 1869 | vec3: F3(V3.$), 1870 | v3getX: V3.getX, 1871 | v3getY: V3.getY, 1872 | v3getZ: V3.getZ, 1873 | v3setX: F2(V3.setX), 1874 | v3setY: F2(V3.setY), 1875 | v3setZ: F2(V3.setZ), 1876 | toTuple3: V3.toTuple3, 1877 | toRecord3: V3.toRecord3, 1878 | fromTuple3: V3.fromTuple3, 1879 | fromRecord3: V3.fromRecord3, 1880 | v3add: F2(V3.add), 1881 | v3sub: F2(V3.sub), 1882 | v3neg: V3.neg, 1883 | v3direction: F2(V3.direction), 1884 | v3length: V3.length, 1885 | v3lengthSquared: V3.lengthSquared, 1886 | v3distance: F2(V3.distance), 1887 | v3distanceSquared: F2(V3.distanceSquared), 1888 | v3normalize: V3.normalize, 1889 | v3scale: F2(V3.scale), 1890 | v3dot: F2(V3.dot), 1891 | v3cross: F2(V3.cross), 1892 | v3mul4x4: F2(V3.mul4x4), 1893 | m4x4fromList: M4x4.fromList, 1894 | m4x4fromRecord: M4x4.fromRecord, 1895 | m4x4toRecord: M4x4.toRecord, 1896 | m4x4identity: M4x4.identity, 1897 | m4x4topLeft3x3: M4x4.topLeft3x3, 1898 | m4x4inverse: M4x4.inverse, 1899 | m4x4inverseOrthonormal: M4x4.inverseOrthonormal, 1900 | m4x4inverseTo3x3: M4x4.inverseTo3x3, 1901 | m4x4makeFrustum: F6(M4x4.makeFrustum), 1902 | m4x4makePerspective: F4(M4x4.makePerspective), 1903 | m4x4makeOrtho: F6(M4x4.makeOrtho), 1904 | m4x4makeOrtho2D: F4(M4x4.makeOrtho2D), 1905 | m4x4mul: F2(M4x4.mul), 1906 | m4x4mulAffine: F2(M4x4.mulAffine), 1907 | m4x4makeRotate: F2(M4x4.makeRotate), 1908 | m4x4rotate: F3(M4x4.rotate), 1909 | m4x4makeScale3: F3(M4x4.makeScale3), 1910 | m4x4makeScale1: M4x4.makeScale1, 1911 | m4x4makeScale: M4x4.makeScale, 1912 | m4x4scale3: F4(M4x4.scale3), 1913 | m4x4scale: F2(M4x4.scale), 1914 | m4x4makeTranslate3: F3(M4x4.makeTranslate3), 1915 | m4x4makeTranslate: M4x4.makeTranslate, 1916 | m4x4translate3: F4(M4x4.translate3), 1917 | m4x4translate: F2(M4x4.translate), 1918 | m4x4makeLookAt: F3(M4x4.makeLookAt), 1919 | m4x4transpose: M4x4.transpose, 1920 | m4x4transformPoint: F2(M4x4.transformPoint), 1921 | m4x4makeBasis: F3(M4x4.makeBasis) 1922 | }; 1923 | 1924 | }(); 1925 | --------------------------------------------------------------------------------