From 20648859974c29a9459178197492c7bf84c058f8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fe=CC=81lix=20Pe=CC=81ault?= Date: Thu, 2 Apr 2020 20:55:20 +0200 Subject: [PATCH] WIP Interactive globe from Nico's sources - The globe is a bit small? Ability to control the max-min size potentially - Is there a reason why `globe.update()` runs every second? Sounds like a lot of resources? - Have the ability to control the `addEventListener` of the markers to do whatever (in this case, going to a route by clicking on a link with a sapper-noscroll attribute + changing the href attribute on click - the method `goto` from Sapper scrolls back to top / maybe something to fix with the current transition issues?) - Edited in `./index.js`: 1. Using the class as `export default WebglGlobe` instead of Window (as Svelte or Sapper doesn't likayt) - Edited in `Camera.js`: 1. Commented line 218: `e.preventDefault();` would cause this error: `[Intervention] Unable to preventDefault inside passive event listener due to target being treated as passive. See ` --- package.json | 1 + pnpm-lock.yaml | 293 +++ rollup.config.js | 4 + src/globe/beam/ArrayBuffer.js | 26 + src/globe/beam/BoxGeometryBuffer.js | 120 ++ src/globe/beam/Camera.js | 393 ++++ src/globe/beam/Container.js | 53 + src/globe/beam/CubeTexture.js | 155 ++ src/globe/beam/DepthTexture.js | 64 + src/globe/beam/FrameBuffer.js | 231 +++ src/globe/beam/FrameBuffer.new.js | 74 + src/globe/beam/GeometryBuffer.js | 30 + src/globe/beam/HDRTexture.js | 207 ++ src/globe/beam/JSONGeometryBuffer.js | 84 + src/globe/beam/Light.js | 98 + src/globe/beam/Loader.js | 33 + src/globe/beam/Material.js | 54 + src/globe/beam/Mesh.js | 90 + src/globe/beam/ObjGeometryBuffer.js | 68 + src/globe/beam/Object3d.js | 170 ++ src/globe/beam/ParticleSystem.js | 117 ++ src/globe/beam/PlaneGeometryBuffer.js | 94 + src/globe/beam/Program.js | 448 +++++ src/globe/beam/RGBEParser.js | 331 ++++ src/globe/beam/Renderer.js | 103 + src/globe/beam/Scene.js | 114 ++ src/globe/beam/SphereGeometryBuffer.js | 112 ++ src/globe/beam/Sprite.js | 35 + src/globe/beam/Texture.js | 247 +++ src/globe/beam/TriangleGeometryBuffer.js | 32 + src/globe/beam/glMatrix/common.js | 62 + src/globe/beam/glMatrix/mat2.js | 433 +++++ src/globe/beam/glMatrix/mat2d.js | 466 +++++ src/globe/beam/glMatrix/mat3.js | 765 ++++++++ src/globe/beam/glMatrix/mat4.js | 1681 +++++++++++++++++ src/globe/beam/glMatrix/old/common.js | 68 + src/globe/beam/glMatrix/old/mat2.js | 237 +++ src/globe/beam/glMatrix/old/mat2d.js | 253 +++ src/globe/beam/glMatrix/old/mat3.js | 478 +++++ src/globe/beam/glMatrix/old/mat4.js | 908 +++++++++ src/globe/beam/glMatrix/old/quat.js | 531 ++++++ src/globe/beam/glMatrix/old/vec2.js | 538 ++++++ src/globe/beam/glMatrix/old/vec3.js | 562 ++++++ src/globe/beam/glMatrix/old/vec4.js | 526 ++++++ src/globe/beam/glMatrix/quat.js | 626 ++++++ src/globe/beam/glMatrix/vec2.js | 584 ++++++ src/globe/beam/glMatrix/vec3.js | 776 ++++++++ src/globe/beam/glMatrix/vec4.js | 606 ++++++ src/globe/beam/index.js | 27 + src/globe/beam/shaders/default-fs.glsl | 8 + src/globe/beam/shaders/default-vs.glsl | 14 + src/globe/beam/shaders/mesh-fs.glsl | 33 + src/globe/beam/shaders/particle-fs.glsl | 11 + .../beam/shaders/particle-position-fs.glsl | 62 + .../beam/shaders/particle-velocity-fs.glsl | 135 ++ src/globe/beam/shaders/particle-vs.glsl | 38 + src/globe/beam/uniformTypes.js | 20 + src/globe/beam/utils/getFilter.js | 12 + src/globe/beam/utils/isPowerOf2.js | 5 + src/globe/beam/utils/uuid.js | 31 + src/globe/beam/utils/warn.js | 3 + src/globe/beam/webgl-obj-loader.js | 396 ++++ src/globe/globe-fs.glsl | 59 + src/globe/globe-fs.js | 60 + src/globe/globe-vs.glsl | 20 + src/globe/globe-vs.js | 22 + src/globe/index.js | 286 +++ src/globe/settings.js | 12 + src/globe/utils/support.js | 47 + src/molecules/InteractiveGlobe.svelte | 100 +- src/style/molecules/_globe.scss | 91 +- static/img/globe/map-4k.png | Bin 0 -> 69459 bytes static/img/icons/zoom-out.svg | 3 - 73 files changed, 15339 insertions(+), 137 deletions(-) create mode 100755 src/globe/beam/ArrayBuffer.js create mode 100755 src/globe/beam/BoxGeometryBuffer.js create mode 100755 src/globe/beam/Camera.js create mode 100755 src/globe/beam/Container.js create mode 100755 src/globe/beam/CubeTexture.js create mode 100755 src/globe/beam/DepthTexture.js create mode 100755 src/globe/beam/FrameBuffer.js create mode 100755 src/globe/beam/FrameBuffer.new.js create mode 100755 src/globe/beam/GeometryBuffer.js create mode 100755 src/globe/beam/HDRTexture.js create mode 100644 src/globe/beam/JSONGeometryBuffer.js create mode 100755 src/globe/beam/Light.js create mode 100755 src/globe/beam/Loader.js create mode 100755 src/globe/beam/Material.js create mode 100755 src/globe/beam/Mesh.js create mode 100755 src/globe/beam/ObjGeometryBuffer.js create mode 100755 src/globe/beam/Object3d.js create mode 100755 src/globe/beam/ParticleSystem.js create mode 100755 src/globe/beam/PlaneGeometryBuffer.js create mode 100755 src/globe/beam/Program.js create mode 100644 src/globe/beam/RGBEParser.js create mode 100755 src/globe/beam/Renderer.js create mode 100755 src/globe/beam/Scene.js create mode 100755 src/globe/beam/SphereGeometryBuffer.js create mode 100755 src/globe/beam/Sprite.js create mode 100755 src/globe/beam/Texture.js create mode 100755 src/globe/beam/TriangleGeometryBuffer.js create mode 100755 src/globe/beam/glMatrix/common.js create mode 100755 src/globe/beam/glMatrix/mat2.js create mode 100755 src/globe/beam/glMatrix/mat2d.js create mode 100755 src/globe/beam/glMatrix/mat3.js create mode 100755 src/globe/beam/glMatrix/mat4.js create mode 100755 src/globe/beam/glMatrix/old/common.js create mode 100755 src/globe/beam/glMatrix/old/mat2.js create mode 100755 src/globe/beam/glMatrix/old/mat2d.js create mode 100755 src/globe/beam/glMatrix/old/mat3.js create mode 100755 src/globe/beam/glMatrix/old/mat4.js create mode 100755 src/globe/beam/glMatrix/old/quat.js create mode 100755 src/globe/beam/glMatrix/old/vec2.js create mode 100755 src/globe/beam/glMatrix/old/vec3.js create mode 100755 src/globe/beam/glMatrix/old/vec4.js create mode 100755 src/globe/beam/glMatrix/quat.js create mode 100755 src/globe/beam/glMatrix/vec2.js create mode 100755 src/globe/beam/glMatrix/vec3.js create mode 100755 src/globe/beam/glMatrix/vec4.js create mode 100755 src/globe/beam/index.js create mode 100755 src/globe/beam/shaders/default-fs.glsl create mode 100755 src/globe/beam/shaders/default-vs.glsl create mode 100755 src/globe/beam/shaders/mesh-fs.glsl create mode 100755 src/globe/beam/shaders/particle-fs.glsl create mode 100755 src/globe/beam/shaders/particle-position-fs.glsl create mode 100755 src/globe/beam/shaders/particle-velocity-fs.glsl create mode 100755 src/globe/beam/shaders/particle-vs.glsl create mode 100755 src/globe/beam/uniformTypes.js create mode 100755 src/globe/beam/utils/getFilter.js create mode 100755 src/globe/beam/utils/isPowerOf2.js create mode 100755 src/globe/beam/utils/uuid.js create mode 100755 src/globe/beam/utils/warn.js create mode 100755 src/globe/beam/webgl-obj-loader.js create mode 100644 src/globe/globe-fs.glsl create mode 100644 src/globe/globe-fs.js create mode 100644 src/globe/globe-vs.glsl create mode 100644 src/globe/globe-vs.js create mode 100644 src/globe/index.js create mode 100644 src/globe/settings.js create mode 100644 src/globe/utils/support.js create mode 100644 static/img/globe/map-4k.png delete mode 100644 static/img/icons/zoom-out.svg diff --git a/package.json b/package.json index 173782a..d67d9f3 100644 --- a/package.json +++ b/package.json @@ -54,6 +54,7 @@ "rollup": "^2.3.2", "rollup-plugin-babel": "^4.4.0", "rollup-plugin-eslint": "^7.0.0", + "rollup-plugin-glslify": "^1.2.0", "rollup-plugin-svelte": "^5.2.0", "rollup-plugin-terser": "^5.3.0", "sapper": "^0.27.12", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 2482113..f3b5147 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -36,6 +36,7 @@ devDependencies: rollup: 2.3.2 rollup-plugin-babel: 4.4.0_@babel+core@7.9.0+rollup@2.3.2 rollup-plugin-eslint: 7.0.0 + rollup-plugin-glslify: 1.2.0 rollup-plugin-svelte: 5.2.0_rollup@2.3.2+svelte@3.20.1 rollup-plugin-terser: 5.3.0_rollup@2.3.2 sapper: 0.27.12_svelte@3.20.1 @@ -878,6 +879,13 @@ packages: dev: true resolution: integrity: sha512-BS9JKfXkzzJl8RluW4JGknzpiUV7ZrvTayM6yfqLTVBEnFtyowVIOu6rqxRd5cVO6yGoWf4T8u8dgK9oB+GCng== + /@choojs/findup/0.2.1: + dependencies: + commander: 2.20.3 + dev: true + hasBin: true + resolution: + integrity: sha512-YstAqNb0MCN8PjdLCDfRsBcGVRN41f3vgLvaI0IrIcBp4AqILRSS0DeWNGkicC+f/zRIPJLc+9RURVSepwvfBw== /@csstools/convert-colors/1.4.0: dev: true engines: @@ -1195,6 +1203,13 @@ packages: dev: true resolution: integrity: sha1-pDAdOJtqQ/m2f/PKEaP2Y342Dp4= + /bl/1.2.2: + dependencies: + readable-stream: 2.3.7 + safe-buffer: 5.2.0 + dev: true + resolution: + integrity: sha512-e8tQYnZodmebYDWGH7KMRvtzKXaJHx3BbilrgZCfvyLUYdKpK1t5PSPmpkny/SgiTSCnjfLW7v5rlONXVFkQEA== /block-stream/0.0.9: dependencies: inherits: 2.0.4 @@ -1429,6 +1444,17 @@ packages: dev: true resolution: integrity: sha1-2Klr13/Wjfd5OnMDajug1UBdR3s= + /concat-stream/1.6.2: + dependencies: + buffer-from: 1.1.1 + inherits: 2.0.4 + readable-stream: 2.3.7 + typedarray: 0.0.6 + dev: true + engines: + '0': node >= 0.8 + resolution: + integrity: sha512-27HBghJxjiZtIk3Ycvn/4kbJk/1uZuJFfuPEns6LaEvpvG1f0hTea8lilrouyo9mVc2GWdcEZ8OLoGmSADlrCw== /console-control-strings/1.1.0: dev: true resolution: @@ -1616,6 +1642,15 @@ packages: node: '>=8' resolution: integrity: sha512-8sJ78ElpbDJBHNeBzUbUVLsqKdccaa/BXF1uPTw3GrvQTBgrQrtObr2mUrE38vzYd8cEv+m/JBfDLioYcfXoaw== + /duplexify/3.7.1: + dependencies: + end-of-stream: 1.4.4 + inherits: 2.0.4 + readable-stream: 2.3.7 + stream-shift: 1.0.1 + dev: true + resolution: + integrity: sha512-07z8uv2wMyS51kKhD1KsdXJg5WQ6t93RneqRxUHnskXVtlYYkLqM0gqStQZ3pj073g687jPCHrqNfCzawLYh5g== /ecc-jsbn/0.1.2: dependencies: jsbn: 0.1.1 @@ -1635,6 +1670,12 @@ packages: dev: true resolution: integrity: sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A== + /end-of-stream/1.4.4: + dependencies: + once: 1.4.0 + dev: true + resolution: + integrity: sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q== /error-ex/1.3.2: dependencies: is-arrayish: 0.2.1 @@ -1675,6 +1716,20 @@ packages: node: '>=0.8.0' resolution: integrity: sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ= + /escodegen/1.14.1: + dependencies: + esprima: 4.0.1 + estraverse: 4.3.0 + esutils: 2.0.3 + optionator: 0.8.3 + dev: true + engines: + node: '>=4.0' + hasBin: true + optionalDependencies: + source-map: 0.6.1 + resolution: + integrity: sha512-Bmt7NcRySdIfNPfU2ZoXDrrXsG9ZjvDxcAlMfDUgRBjLOWTuIACXPBFJH7Z+cLb40JeQco5toikyc9t9P8E9SQ== /eslint-config-standard/14.1.1_ba4e39e016526c0b815f06ce4b4a873a: dependencies: eslint-plugin-import: 2.20.2 @@ -1913,6 +1968,12 @@ packages: dev: false resolution: integrity: sha512-ipiDYhdQSCZ4hSbX4rMW+XzNKMD1prg/sTvoVmSLkuQ1MVlwjJQQA+sW8tMYR3BLUr9KjodFV4pvzunvRhd33Q== + /events/1.1.1: + dev: true + engines: + node: '>=0.4.x' + resolution: + integrity: sha1-nr23Y1rQmccNzEwqH1AEKI6L2SQ= /extend/3.0.2: dev: true resolution: @@ -1933,6 +1994,17 @@ packages: '0': node >=0.6.0 resolution: integrity: sha1-lpGEQOMEGnpBT4xS48V06zw+HgU= + /falafel/2.2.4: + dependencies: + acorn: 7.1.1 + foreach: 2.0.5 + isarray: 2.0.5 + object-keys: 1.1.1 + dev: true + engines: + node: '>=0.4.0' + resolution: + integrity: sha512-0HXjo8XASWRmsS0X1EkhwEMZaD3Qvp7FfURwjLKjG1ghfRm/MGZl2r4cWUTv41KdNghTw4OUMmVtdGQp3+H+uQ== /fast-deep-equal/3.1.1: dev: true resolution: @@ -2013,6 +2085,10 @@ packages: dev: true resolution: integrity: sha512-dVsPA/UwQ8+2uoFe5GHtiBMu48dWLTdsuEd7CKGlZlD78r1TTWBvDuFaFGKCo/ZfEr95Uk56vZoX86OsHkUeIg== + /foreach/2.0.5: + dev: true + resolution: + integrity: sha1-C+4AUBiusmDQo6865ljdATbsG5k= /forever-agent/0.6.1: dev: true resolution: @@ -2027,6 +2103,13 @@ packages: node: '>= 0.12' resolution: integrity: sha512-1lLKB2Mu3aGP1Q/2eCOx0fNbRMe7XdwktwOruhfqqd0rIJWwN4Dh+E3hrPSlDCXnSR7UtZ1N38rVXm+6+MEhJQ== + /from2/2.3.0: + dependencies: + inherits: 2.0.4 + readable-stream: 2.3.7 + dev: true + resolution: + integrity: sha1-i/tVAr3kpNNs/e6gB/zKIdfjgq8= /fs.realpath/1.0.0: dev: true resolution: @@ -2145,6 +2228,119 @@ packages: node: '>= 0.10' resolution: integrity: sha512-OVyWOHgw29yosRHCHo7NncwR1hW5ew0W/UrvtwvjefVJeQ26q4/8r8FmPsSF1hJ93IgWkyv16pCTz6WblMzm/g== + /glsl-inject-defines/1.0.3: + dependencies: + glsl-token-inject-block: 1.1.0 + glsl-token-string: 1.0.1 + glsl-tokenizer: 2.1.5 + dev: true + resolution: + integrity: sha1-3RqswsF/yyvT/DJBHGYz0Ne2D9Q= + /glsl-resolve/0.0.1: + dependencies: + resolve: 0.6.3 + xtend: 2.2.0 + dev: true + resolution: + integrity: sha1-iUvvc5ENeSyBtRQxgANdCnivdtM= + /glsl-token-assignments/2.0.2: + dev: true + resolution: + integrity: sha1-pdgqt4SZwuimuDy2lJXm5mXOAZ8= + /glsl-token-defines/1.0.0: + dependencies: + glsl-tokenizer: 2.1.5 + dev: true + resolution: + integrity: sha1-y4kqqVmTYjFyhHDU90AySJaX+p0= + /glsl-token-depth/1.1.2: + dev: true + resolution: + integrity: sha1-I8XjDuK9JViEtKKLyFC495HpXYQ= + /glsl-token-descope/1.0.2: + dependencies: + glsl-token-assignments: 2.0.2 + glsl-token-depth: 1.1.2 + glsl-token-properties: 1.0.1 + glsl-token-scope: 1.1.2 + dev: true + resolution: + integrity: sha1-D8kKsyYYa4L1l7LnfcniHvzTIHY= + /glsl-token-inject-block/1.1.0: + dev: true + resolution: + integrity: sha1-4QFfWYDBCRgkraomJfHf3ovQADQ= + /glsl-token-properties/1.0.1: + dev: true + resolution: + integrity: sha1-SD3D2Dnw1LXGFx0VkfJJvlPCip4= + /glsl-token-scope/1.1.2: + dev: true + resolution: + integrity: sha1-oXKOeN8kRE+cuT/RjvD3VQOmQ7E= + /glsl-token-string/1.0.1: + dev: true + resolution: + integrity: sha1-WUQdL4V958NEnJRWZgIezjWOSOw= + /glsl-token-whitespace-trim/1.0.0: + dev: true + resolution: + integrity: sha1-RtHf6Yx1vX1QTAXX0RsbPpzJOxA= + /glsl-tokenizer/2.1.5: + dependencies: + through2: 0.6.5 + dev: true + resolution: + integrity: sha512-XSZEJ/i4dmz3Pmbnpsy3cKh7cotvFlBiZnDOwnj/05EwNp2XrhQ4XKJxT7/pDt4kp4YcpRSKz8eTV7S+mwV6MA== + /glslify-bundle/5.1.1: + dependencies: + glsl-inject-defines: 1.0.3 + glsl-token-defines: 1.0.0 + glsl-token-depth: 1.1.2 + glsl-token-descope: 1.0.2 + glsl-token-scope: 1.1.2 + glsl-token-string: 1.0.1 + glsl-token-whitespace-trim: 1.0.0 + glsl-tokenizer: 2.1.5 + murmurhash-js: 1.0.0 + shallow-copy: 0.0.1 + dev: true + resolution: + integrity: sha512-plaAOQPv62M1r3OsWf2UbjN0hUYAB7Aph5bfH58VxJZJhloRNbxOL9tl/7H71K7OLJoSJ2ZqWOKk3ttQ6wy24A== + /glslify-deps/1.3.1: + dependencies: + '@choojs/findup': 0.2.1 + events: 1.1.1 + glsl-resolve: 0.0.1 + glsl-tokenizer: 2.1.5 + graceful-fs: 4.2.3 + inherits: 2.0.4 + map-limit: 0.0.1 + resolve: 1.15.1 + dev: true + resolution: + integrity: sha512-Ogm179MCazwIRyEqs3g3EOY4Y3XIAa0yl8J5RE9rJC6QH1w8weVOp2RZu0mvnYy/2xIas1w166YR2eZdDkWQxg== + /glslify/7.0.0: + dependencies: + bl: 1.2.2 + concat-stream: 1.6.2 + duplexify: 3.7.1 + falafel: 2.2.4 + from2: 2.3.0 + glsl-resolve: 0.0.1 + glsl-token-whitespace-trim: 1.0.0 + glslify-bundle: 5.1.1 + glslify-deps: 1.3.1 + minimist: 1.2.5 + resolve: 1.15.1 + stack-trace: 0.0.9 + static-eval: 2.0.5 + through2: 2.0.5 + xtend: 4.0.2 + dev: true + hasBin: true + resolution: + integrity: sha512-yw8jDQIe9FlSH5NiZEqSAsCPj9HI7nhXgXLAgSv2Nm9eBPsFJmyN9+rNwbiozJapcj9xtc/71rMYlN9cxp1B8Q== /graceful-fs/4.2.3: dev: true resolution: @@ -2475,10 +2671,18 @@ packages: dev: true resolution: integrity: sha1-Sw2hRCEE0bM2NA6AeX6GXPOffXI= + /isarray/0.0.1: + dev: true + resolution: + integrity: sha1-ihis/Kmo9Bd+Cav8YDiTmwXR7t8= /isarray/1.0.0: dev: true resolution: integrity: sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE= + /isarray/2.0.5: + dev: true + resolution: + integrity: sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw== /isexe/2.0.0: dev: true resolution: @@ -2703,6 +2907,12 @@ packages: dev: true resolution: integrity: sha512-4CrMT5DOHTDk4HYDlzmwu4FVCcIYI8gauveasrdCu2IKIFOJ3f0v/8MDGJCDL9oD2ppz/Av1b0Nj345H9M+XIA== + /map-limit/0.0.1: + dependencies: + once: 1.3.3 + dev: true + resolution: + integrity: sha1-63lhAxwPDo0AG/LVb6toXViCLzg= /map-obj/1.0.1: dev: true engines: @@ -2786,6 +2996,10 @@ packages: dev: true resolution: integrity: sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w== + /murmurhash-js/1.0.0: + dev: true + resolution: + integrity: sha1-sGJ44h/Gw3+lMTcysEEry2rhX1E= /mute-stream/0.0.8: dev: true resolution: @@ -2963,6 +3177,12 @@ packages: node: '>= 0.8' resolution: integrity: sha512-pZAE+FJLoyITytdqK0U5s+FIpjN0JP3OzFi/u8Rx+EV5/W+JTWGXG8xFzevE7AjBfDqHv/8vL8qQsIhHnqRkrA== + /once/1.3.3: + dependencies: + wrappy: 1.0.2 + dev: true + resolution: + integrity: sha1-suJhVXzkwxTsgwTz+oJmPkKXyiA= /once/1.4.0: dependencies: wrappy: 1.0.2 @@ -3605,6 +3825,15 @@ packages: node: '>=4' resolution: integrity: sha1-jvHAYjxqbbDcZxPEv6xGMysjaPg= + /readable-stream/1.0.34: + dependencies: + core-util-is: 1.0.2 + inherits: 2.0.4 + isarray: 0.0.1 + string_decoder: 0.10.31 + dev: true + resolution: + integrity: sha1-Elgg40vIQtLyqq+v5MKRbuMsFXw= /readable-stream/2.3.7: dependencies: core-util-is: 1.0.2 @@ -3763,6 +3992,10 @@ packages: node: '>=4' resolution: integrity: sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g== + /resolve/0.6.3: + dev: true + resolution: + integrity: sha1-3ZV5gufnNt699TtYpN2RdUV13UY= /resolve/1.15.1: dependencies: path-parse: 1.0.6 @@ -3811,6 +4044,13 @@ packages: dev: true resolution: integrity: sha512-u35kXiY11ULeNQGTlRkYx7uGJ/hS/Dx3wj8f9YVC3oMLTGU9fOqQJsAKYtBFZU3gJ8Vt3gu8ppB1vnKl+7gatQ== + /rollup-plugin-glslify/1.2.0: + dependencies: + glslify: 7.0.0 + rollup-pluginutils: 2.8.2 + dev: true + resolution: + integrity: sha512-EqUFINMICD9U3MJ4jsxBcCRhzWNZJBWyAK2ol+2ClWIPaIWOuz0OY/Ml8rdT81F4aufwxJN5I9N7QvCth0OrUQ== /rollup-plugin-svelte/5.2.0_rollup@2.3.2+svelte@3.20.1: dependencies: require-relative: 0.8.7 @@ -3942,6 +4182,10 @@ packages: dev: true resolution: integrity: sha1-BF+XgtARrppoA93TgrJDkrPYkPc= + /shallow-copy/0.0.1: + dev: true + resolution: + integrity: sha1-QV9CcC1z2BAzApLMXuhurhoRoXA= /shebang-command/1.2.0: dependencies: shebang-regex: 1.0.0 @@ -4063,12 +4307,26 @@ packages: hasBin: true resolution: integrity: sha512-HXXqVUq7+pcKeLqqZj6mHFUMvXtOJt1uoUx09pFW6011inTMxqI8BA8PM95myrIyyKwdnzjdFjLiE6KBPVtJIg== + /stack-trace/0.0.9: + dev: true + resolution: + integrity: sha1-qPbq7KkGdMMz58Q5U/J1tFFRBpU= + /static-eval/2.0.5: + dependencies: + escodegen: 1.14.1 + dev: true + resolution: + integrity: sha512-nNbV6LbGtMBgv7e9LFkt5JV8RVlRsyJrphfAt9tOtBBW/SfnzZDf2KnS72an8e434A+9e/BmJuTxeGPvrAK7KA== /stdout-stream/1.4.1: dependencies: readable-stream: 2.3.7 dev: true resolution: integrity: sha512-j4emi03KXqJWcIeF8eIXkjMFN1Cmb8gUlDYGeBALLPo5qdyTfA9bOtl8m33lRoC+vFMkP3gl0WsDr6+gzxbbTA== + /stream-shift/1.0.1: + dev: true + resolution: + integrity: sha512-AiisoFqQ0vbGcZgQPY1cdP2I76glaVA/RauYR4G4thNFgkTqr90yXTo4LYX60Jl+sIlPNHHdGSwo01AvbKUSVQ== /string-hash/1.1.3: dev: true resolution: @@ -4121,6 +4379,10 @@ packages: node: '>= 0.4' resolution: integrity: sha512-qFvWL3/+QIgZXVmJBfpHmxLB7xsUXz6HsUmP8+5dRaC3Q7oKUv9Vo6aMCRZC1smrtyECFsIT30PqBJ1gTjAs+g== + /string_decoder/0.10.31: + dev: true + resolution: + integrity: sha1-YuIDvEF2bGwoyfyEMB2rHFMQ+pQ= /string_decoder/1.1.1: dependencies: safe-buffer: 5.1.2 @@ -4281,6 +4543,20 @@ packages: dev: true resolution: integrity: sha1-DdTJ/6q8NXlgsbckEV1+Doai4fU= + /through2/0.6.5: + dependencies: + readable-stream: 1.0.34 + xtend: 4.0.2 + dev: true + resolution: + integrity: sha1-QaucZ7KdVyCQcUEOHXp6lozTrUg= + /through2/2.0.5: + dependencies: + readable-stream: 2.3.7 + xtend: 4.0.2 + dev: true + resolution: + integrity: sha512-/mrRod8xqpA+IHSLyGCQ2s8SPHiCDEeQJSep1jqLYeEUClOFG2Qsh+4FU6G9VeqpZnGW/Su8LQGc4YKni5rYSQ== /tmp/0.0.33: dependencies: os-tmpdir: 1.0.2 @@ -4358,6 +4634,10 @@ packages: node: '>=8' resolution: integrity: sha512-4dbzIzqvjtgiM5rw1k5rEHtBANKmdudhGyBEajN01fEyhaAIhsoKNy6y7+IN93IfpFtwY9iqi7kD+xwKhQsNJA== + /typedarray/0.0.6: + dev: true + resolution: + integrity: sha1-hnrHTjhkGHsdPUfZlqeOxciDB3c= /uglify-js/3.8.1: dependencies: commander: 2.20.3 @@ -4489,6 +4769,18 @@ packages: node: '>=4' resolution: integrity: sha512-/lg70HAjtkUgWPVZhZcm+T4hkL8Zbtp1nFNOn3lRrxnlv50SRBv7cR7RqR+GMsd3hUXy9hWBo4CHTbFTcOYwig== + /xtend/2.2.0: + dev: true + engines: + node: '>=0.4' + resolution: + integrity: sha1-7vax8ZjByN6vrYsXZaBNrUoBxak= + /xtend/4.0.2: + dev: true + engines: + node: '>=0.4' + resolution: + integrity: sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ== /y18n/3.2.1: dev: true resolution: @@ -4558,6 +4850,7 @@ specifiers: rollup: ^2.3.2 rollup-plugin-babel: ^4.4.0 rollup-plugin-eslint: ^7.0.0 + rollup-plugin-glslify: ^1.2.0 rollup-plugin-svelte: ^5.2.0 rollup-plugin-terser: ^5.3.0 sapper: ^0.27.12 diff --git a/rollup.config.js b/rollup.config.js index 0790896..5873f70 100644 --- a/rollup.config.js +++ b/rollup.config.js @@ -9,6 +9,7 @@ import babel from 'rollup-plugin-babel' // import browsersync from 'rollup-plugin-browsersync' import autoPreprocess from 'svelte-preprocess' import { terser } from 'rollup-plugin-terser' +import glslify from 'rollup-plugin-glslify' import sapperConfig from 'sapper/config/rollup' import { config } from 'dotenv' import pkg from './package.json' @@ -44,6 +45,7 @@ const aliases = alias({ { find: 'atoms', replacement: path.resolve(__dirname, 'src/atoms') }, { find: 'molecules', replacement: path.resolve(__dirname, 'src/molecules') }, { find: 'organisms', replacement: path.resolve(__dirname, 'src/organisms') }, + { find: 'globe', replacement: path.resolve(__dirname, 'src/globe') }, ] }) @@ -69,6 +71,7 @@ export default { // css: css => css.write('static/bundle.css') }), aliases, + glslify(), resolve({ browser: true, extensions: resolveExtensions, @@ -109,6 +112,7 @@ export default { generate: 'ssr' }), aliases, + glslify(), resolve({ browser: true, extensions: resolveExtensions, diff --git a/src/globe/beam/ArrayBuffer.js b/src/globe/beam/ArrayBuffer.js new file mode 100755 index 0000000..51b0431 --- /dev/null +++ b/src/globe/beam/ArrayBuffer.js @@ -0,0 +1,26 @@ +class ArrayBuffer { + + constructor(gl, data, size, element, name) { + this.name = name; + this.gl = gl; + this._buffer = this.gl.createBuffer(); + this.type = this.gl.FLOAT; + this._target = this.gl[ element ? 'ELEMENT_ARRAY_BUFFER' : 'ARRAY_BUFFER' ]; + this.update(data, size); + } + + update(data, size) { + this.data = data; + this.size = size; + this.length = this.data.length; + this.gl.bindBuffer( this._target, this._buffer); + this.gl.bufferData( this._target, this.data, this.gl.STATIC_DRAW); + } + + bind() { + this.gl.bindBuffer( this._target, this._buffer ); + } + +} + +export default ArrayBuffer; \ No newline at end of file diff --git a/src/globe/beam/BoxGeometryBuffer.js b/src/globe/beam/BoxGeometryBuffer.js new file mode 100755 index 0000000..c277508 --- /dev/null +++ b/src/globe/beam/BoxGeometryBuffer.js @@ -0,0 +1,120 @@ +import GeometryBuffer from './GeometryBuffer'; +import * as vec3 from './glMatrix/vec3'; + + + + + +class BoxGeometryBuffer extends GeometryBuffer { + + constructor(gl, options) { + + super(gl, 4.); + + options = Object.assign({},{ + width: 10, + height: 10, + depth: 10, + widthSegments: 1, + heightSegments: 1, + depthSegments: 1 + }, options); + + // buffers + var indices = []; + var vertices = []; + var normals = []; + var uvs = []; + var colors = [] + + var numberOfVertices = 0; + var vertexCounter = 0; + + function buildPlane( u, v, w, udir, vdir, width, height, depth, gridX, gridY ) { + + vertexCounter = 0; + + var segmentWidth = width / gridX; + var segmentHeight = height / gridY; + var widthHalf = width / 2; + var heightHalf = height / 2; + var depthHalf = depth / 2; + var gridX1 = gridX + 1; + var gridY1 = gridY + 1; + var ix, iy; + + var vector = vec3.create(); + + // generate vertices, normals and uvs + + for ( iy = 0; iy < gridY1; iy ++ ) { + + var y = iy * segmentHeight - heightHalf; + + for ( ix = 0; ix < gridX1; ix ++ ) { + + var x = ix * segmentWidth - widthHalf; + + vector[ u ] = x * udir; + vector[ v ] = y * vdir; + vector[ w ] = depthHalf; + vertices.push( vector[0], vector[1], vector[2] ); + + vector[ u ] = 1.; + vector[ v ] = 1.; + vector[ w ] = 1.; + + vector[ u ] = 0; + vector[ v ] = 0; + vector[ w ] = depth > 0 ? 1 : -1; + normals.push( vector[0], vector[1], vector[2] ); + + uvs.push( ix / gridX, 1 - ( iy / gridY ) ); + + colors.push( 1, 1, 1 ); + + vertexCounter += 1; + + } + + } + + for ( iy = 0; iy < gridY; iy ++ ) { + for ( ix = 0; ix < gridX; ix ++ ) { + var a = numberOfVertices + ix + gridX1 * iy; + var b = numberOfVertices + ix + gridX1 * ( iy + 1 ); + var c = numberOfVertices + ( ix + 1 ) + gridX1 * ( iy + 1 ); + var d = numberOfVertices + ( ix + 1 ) + gridX1 * iy; + // faces + indices.push( a, b, d ); + indices.push( b, c, d ); + } + } + + numberOfVertices += vertexCounter; + } + + + // build each side of the box geometry + buildPlane( 2, 1, 0, - 1, - 1, options.depth, options.height, options.width, Math.floor(options.depthSegments), Math.floor(options.heightSegments) ); // px + buildPlane( 2, 1, 0, 1, - 1, options.depth, options.height, - options.width, Math.floor(options.depthSegments), Math.floor(options.heightSegments) ); // nx + buildPlane( 0, 2, 1, 1, 1, options.width, options.depth, options.height, Math.floor(options.widthSegments), Math.floor(options.depthSegments) ); // py + buildPlane( 0, 2, 1, 1, - 1, options.width, options.depth, - options.height, Math.floor(options.widthSegments), Math.floor(options.depthSegments) ); // ny + buildPlane( 0, 1, 2, 1, - 1, options.width, options.height, options.depth, Math.floor(options.widthSegments), Math.floor(options.heightSegments) ); // pz + buildPlane( 0, 1, 2, - 1, - 1, options.width, options.height, - options.depth, Math.floor(options.widthSegments), Math.floor(options.heightSegments) ); // nz + + + // build geometry + this.length = numberOfVertices; + + this.addAttribute( 'index', new Uint16Array( indices ), 1 ); + this.addAttribute( 'position', new Float32Array( vertices ), 3 ); + this.addAttribute( 'normal', new Float32Array( normals ), 3 ); + this.addAttribute( 'uv', new Float32Array( uvs ), 2 ); + this.addAttribute( 'color', new Float32Array( colors ), 3 ); + + } + +} + +export default BoxGeometryBuffer; \ No newline at end of file diff --git a/src/globe/beam/Camera.js b/src/globe/beam/Camera.js new file mode 100755 index 0000000..4028a8d --- /dev/null +++ b/src/globe/beam/Camera.js @@ -0,0 +1,393 @@ +import Object3d from './Object3d'; +import Container from './Container'; +import * as mat4 from './glMatrix/mat4'; +import * as vec3 from './glMatrix/vec3'; +import * as quat from './glMatrix/quat'; + +const TOUCH = ('ontouchstart' in window) || (navigator.msMaxTouchPoints > 0); +const POINTER = !!window.navigator.pointerEnabled; +const MS_POINTER = !!window.navigator.msPointerEnabled; + +const POINTER_DOWN = TOUCH ? 'touchstart' : (POINTER ? 'pointerdown' : (MS_POINTER ? 'MSPointerDown' : 'mousedown' ) ); +const POINTER_MOVE = TOUCH ? 'touchmove' : (POINTER ? 'pointermove' : (MS_POINTER ? 'MSPointerMove' : 'mousemove' ) ); +const POINTER_UP = TOUCH ? 'touchend' : (POINTER ? 'pointerup' : (MS_POINTER ? 'MSPointerUp' : 'mouseup' ) ); + + + +var objects = [] + +function needsUpdateLoop() { + requestAnimationFrame(needsUpdateLoop); + for (let i=0; i { + // this.gl.bindTexture( this.gl.TEXTURE_CUBE_MAP, this._texture); + // this.gl.texParameteri( this.gl.TEXTURE_CUBE_MAP, this.gl.TEXTURE_WRAP_S, value ); + // } + // }); + // Object.defineProperty(this, 'wrapT', { + // set: (value) => { + // this.gl.bindTexture( this.gl.TEXTURE_CUBE_MAP, this._texture); + // this.gl.texParameteri( this.gl.TEXTURE_CUBE_MAP, this.gl.TEXTURE_WRAP_T, value ); + // } + // }); + // //nPOT texture can't repeat + // this.wrapS = options.wrapS; + // this.wrapT = options.wrapT; + + //nPOT texture cannot mipmap + // this.setFilter( options.linear, options.mipmap, options.mipmapLinear ); + + if (options.urls !== null) { + this.load(options.urls); + } + + } + + load(urls) { + var faces = [ + this.gl.TEXTURE_CUBE_MAP_POSITIVE_X, + this.gl.TEXTURE_CUBE_MAP_NEGATIVE_X, + this.gl.TEXTURE_CUBE_MAP_POSITIVE_Y, + this.gl.TEXTURE_CUBE_MAP_NEGATIVE_Y, + this.gl.TEXTURE_CUBE_MAP_POSITIVE_Z, + this.gl.TEXTURE_CUBE_MAP_NEGATIVE_Z + ]; + for (let i = 0; i < urls.length; i++) { + let face = faces[i]; + let image = new Image(); + image.onload = ()=> { + image.onload = null; + // this.bindFaceImage(face, image); + this.gl.bindTexture(this.gl.TEXTURE_CUBE_MAP, this._texture); + this.gl.pixelStorei(this.gl.UNPACK_FLIP_Y_WEBGL, false); + this.gl.texImage2D(face, 0, this.gl.RGBA, this.gl.RGBA, this.gl.UNSIGNED_BYTE, image); + this.gl.texParameteri(this.gl.TEXTURE_CUBE_MAP, this.gl.TEXTURE_MAG_FILTER, this.gl.LINEAR); + this.gl.texParameteri(this.gl.TEXTURE_CUBE_MAP, this.gl.TEXTURE_MIN_FILTER, this.gl.LINEAR); + this.gl.texParameteri(this.gl.TEXTURE_CUBE_MAP, this.gl.TEXTURE_WRAP_S, this.gl.CLAMP_TO_EDGE); + this.gl.texParameteri(this.gl.TEXTURE_CUBE_MAP, this.gl.TEXTURE_WRAP_T, this.gl.CLAMP_TO_EDGE); + } + image.src = urls[i]; + } + } + + bindFaceImage(face, image) { + this.gl.bindTexture(this.gl.TEXTURE_CUBE_MAP, this._texture); + this.gl.pixelStorei(this.gl.UNPACK_FLIP_Y_WEBGL, false); + if (image._texture) { + this.gl.texImage2D(face, 0, this.format, image.width, image.height, 0, this.format, this.type, image._texture); + } + else { + this.gl.texImage2D(face, 0, this.format, image.width, image.height, 0, this.format, this.type, image); + } + } + + bindFaceFrameBuffer(face, frameBuffer) { + this.gl.bindTexture( this.gl.TEXTURE_CUBE_MAP, this._texture); + this.gl.bindFramebuffer( this.gl.FRAMEBUFFER, frameBuffer.fbo ); + this.gl.framebufferTexture2D(this.gl.FRAMEBUFFER, this.gl.COLOR_ATTACHMENT0, face, this._texture, 0); + let status_code = this.gl.checkFramebufferStatus(this.gl.FRAMEBUFFER); + if (status_code != this.gl.FRAMEBUFFER_COMPLETE) { + if (status_code == this.gl.FRAMEBUFFER_INCOMPLETE_ATTACHMENT) { + console.log('GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT'); + } + if (status_code == this.gl.FRAMEBUFFER_INCOMPLETE_DIMENSIONS) { + console.log('FRAMEBUFFER_INCOMPLETE_DIMENSIONS: Not all attached images have the same width and height.'); + } + if (status_code == this.gl.FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT) { + console.log('FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT: No images are attached to the framebuffer.'); + } + } else { + console.log("success"); + } + // this.gl.bindTexture( this.gl.TEXTURE_CUBE_MAP, null ); + this.gl.bindFramebuffer( this.gl.FRAMEBUFFER, null ); + frameBuffer.unbind(); + } + + bind(unit) { + if( unit !== undefined ){ + this.gl.activeTexture( this.gl.TEXTURE0 + (0|unit) ); + } + this.gl.bindTexture( this.gl.TEXTURE_CUBE_MAP, this._texture ); + } + + delete() { + this.gl.deleteTexture( this._texture ); + this._texture = null; + this.gl = null; + } + +} + +export default CubeTexture; diff --git a/src/globe/beam/DepthTexture.js b/src/globe/beam/DepthTexture.js new file mode 100755 index 0000000..beae8fe --- /dev/null +++ b/src/globe/beam/DepthTexture.js @@ -0,0 +1,64 @@ +class DepthTexture { + + constructor(gl, options) { + + let supportsDepthTexture = gl.getExtension("WEBGL_depth_texture"); + + if (!supportsDepthTexture) { + throw("FrameBuffer useDepthTexture:true => Cannot render depth to texture, the browser doesnt support WEBKIT_WEBGL_depth_texture extension") + } + + options = Object.assign({}, { + width: 1, + height: 1, + type: gl.UNSIGNED_SHORT + }, options); + + this.gl = gl; + this.width = options.width; + this.height = options.height; + this.type = options.type; + + var floatTextures = gl.getExtension('OES_texture_float'); + var floatTextureLinearFiltering = gl.getExtension('OES_texture_float_linear'); + + if (!floatTextures && this.type == gl.FLOAT) { + throw('trying to create a DepthTexture of gl.FLOAT type but there\s no floating point texture support'); + return; + } + + this._texture = this.gl.createTexture(); + this.gl.bindTexture(this.gl.TEXTURE_2D, this._texture); + this.gl.texParameteri(this.gl.TEXTURE_2D, this.gl.TEXTURE_MAG_FILTER, this.gl.NEAREST); + this.gl.texParameteri(this.gl.TEXTURE_2D, this.gl.TEXTURE_MIN_FILTER, this.gl.NEAREST); + this.gl.texParameteri(this.gl.TEXTURE_2D, this.gl.TEXTURE_WRAP_S, this.gl.CLAMP_TO_EDGE); + this.gl.texParameteri(this.gl.TEXTURE_2D, this.gl.TEXTURE_WRAP_T, this.gl.CLAMP_TO_EDGE); + this.gl.texImage2D(this.gl.TEXTURE_2D, 0, this.gl.DEPTH_COMPONENT, this.width, this.height, 0, this.gl.DEPTH_COMPONENT, this.type, null); + gl.bindTexture( gl.TEXTURE_2D, null); + + } + + bind(unit) { + if (unit !== void 0) { + this.gl.activeTexture( this.gl.TEXTURE0 + (0|unit) ); + } + this.gl.bindTexture(this.gl.TEXTURE_2D, this._texture); + } + + delete() { + this.gl.deleteTexture( this._texture ); + this._texture = null; + this.gl = null; + } + + resize(w, h) { + this.width = w; + this.height = h; + this.gl.bindTexture(this.gl.TEXTURE_2D, this._texture); + this.gl.texImage2D(this.gl.TEXTURE_2D, 0, this.gl.DEPTH_COMPONENT, this.width, this.height, 0, this.gl.DEPTH_COMPONENT, this.type, null); + gl.bindTexture( gl.TEXTURE_2D, null); + } + +} + +export default DepthTexture; \ No newline at end of file diff --git a/src/globe/beam/FrameBuffer.js b/src/globe/beam/FrameBuffer.js new file mode 100755 index 0000000..7de702e --- /dev/null +++ b/src/globe/beam/FrameBuffer.js @@ -0,0 +1,231 @@ +import getFilter from './utils/getFilter'; +import isPowerOf2 from './utils/isPowerOf2'; + +class FrameBuffer { + + constructor ( gl, options ) { + + this.options = Object.assign({},{ + format: gl.RGBA, + type: gl.UNSIGNED_BYTE, + linear: true, + mipmap: false, + mipmapLinear: false, + wrapS: gl.CLAMP_TO_EDGE, + wrapT: gl.CLAMP_TO_EDGE, + depthTexture: null + }, options); + + this.gl = gl; + + this.width = this.options.width; + this.height = this.options.height; + this.format = this.options.format; + this.type = this.options.type; + this.linear = this.options.linear; + this.mipmap = this.options.mipmap; + this.mipmapLinear = this.options.mipmapLinear; + + if (this.type == gl.FLOAT) { + var floatTextures = gl.getExtension('OES_texture_float'); + var floatTextureLinearFiltering = gl.getExtension('OES_texture_float_linear'); + if (!floatTextures) { + console.warn('trying to create a FrameBuffer of with gl.FLOAT type but there\s no floating point texture support. trying HALF_FLOAT'); + this.type = "HALF_FLOAT" + } + } + + if (this.type == "HALF_FLOAT") { + var halfFloatTexturesExt = gl.getExtension('OES_texture_half_float'); + var halfFloatTextureLinearFiltering = gl.getExtension('OES_texture_half_float_linear'); + if (!halfFloatTexturesExt) { + console.warn('trying to create a texture of with gl.HALF_FLOAT type but there\s no half floating point texture support; falling bck to UNSIGNED_BYTE type'); + this.type = gl.UNSIGNED_BYTE; + } + else { + this.type = halfFloatTexturesExt.HALF_FLOAT_OES; + this.isHalfFloat = true; + } + } + + this._texture = this.gl.createTexture(); + this.gl.bindTexture(this.gl.TEXTURE_2D, this._texture); + + if (this.type == this.gl.FLOAT) { + this.gl.texImage2D(this.gl.TEXTURE_2D, 0, this.format, this.width, this.height, 0, this.format, this.type, new Float32Array( new Array(this.width * this.height * 4) )); + } + else if (this.isHalfFloat) { + this.gl.texImage2D(this.gl.TEXTURE_2D, 0, this.format, this.width, this.height, 0, this.format, this.type, null); + } + else { + this.gl.texImage2D(this.gl.TEXTURE_2D, 0, this.format, this.width, this.height, 0, this.format, this.type, new Uint8Array( new Array(this.width * this.height * 4) )); + } + + /** + * add getter and setter to update texture_wrap when this.wrap changes + */ + Object.defineProperty(this, 'wrapS', { + set: (value) => { + this.gl.bindTexture(this.gl.TEXTURE_2D, this._texture); + this.gl.texParameteri( this.gl.TEXTURE_2D, this.gl.TEXTURE_WRAP_S, value ); + } + }); + Object.defineProperty(this, 'wrapT', { + set: (value) => { + this.gl.bindTexture(this.gl.TEXTURE_2D, this._texture); + this.gl.texParameteri( this.gl.TEXTURE_2D, this.gl.TEXTURE_WRAP_T, value ); + } + }); + + //nPOT texture can't repeat + this.wrapS = this.options.wrapS; + this.wrapT = this.options.wrapT; + + var isPOT = isPowerOf2(this.width) && isPowerOf2(this.height); + if (!isPOT) { + this.wrapS = gl.CLAMP_TO_EDGE; + this.wrapT = gl.CLAMP_TO_EDGE; + this.mipmap = false; + this.mipmapLinear = false; + } + + //nPOT texture cannot mipmap + this.setFilter( this.linear, this.mipmap, this.mipmapLinear ); + + + if (!this.options.depthTexture) { + this.renderbuffer = this.gl.createRenderbuffer(); + this.gl.bindRenderbuffer(this.gl.RENDERBUFFER, this.renderbuffer); + this.gl.renderbufferStorage(this.gl.RENDERBUFFER, this.gl.DEPTH_COMPONENT16, this.width, this.height); + } + + this.fbo = this.gl.createFramebuffer(); + this.gl.bindFramebuffer( this.gl.FRAMEBUFFER, this.fbo ); + this.gl.framebufferTexture2D(this.gl.FRAMEBUFFER, this.gl.COLOR_ATTACHMENT0, this.gl.TEXTURE_2D, this._texture, 0); + + if (this.options.depthTexture) { + this.gl.framebufferTexture2D(this.gl.FRAMEBUFFER, this.gl.DEPTH_ATTACHMENT, this.gl.TEXTURE_2D, this.options.depthTexture._texture, 0); + } + else { + this.gl.framebufferRenderbuffer(this.gl.FRAMEBUFFER, this.gl.DEPTH_ATTACHMENT, this.gl.RENDERBUFFER, this.renderbuffer); + } + + this.unbind(); + + } + + /** + * [setFilter description] + * @param {[type]} linear [description] + * @param {[type]} mipmap [description] + * @param {[type]} mipmapLinear [description] + */ + setFilter(linear, mipmap, mipmapLinear) { + var gl = this.gl; + var filter = getFilter( !!linear, !!mipmap, !!mipmapLinear); + gl.bindTexture( gl.TEXTURE_2D, this._texture); + gl.texParameteri( gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, getFilter( !!linear, false, false ) ); + gl.texParameteri( gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, filter ); + } + + resize(w, h) { + + if( this.width !== w || this.height !== h ) { + this.width = w|0; + this.height = h|0; + } + + var isPOT = isPowerOf2(this.width) && isPowerOf2(this.height); + if (!isPOT) { + this.wrapS = this.gl.CLAMP_TO_EDGE; + this.wrapT = this.gl.CLAMP_TO_EDGE; + this.mipmap = false; + this.mipmapLinear = false; + this.setFilter( this.linear, this.mipmap, this.mipmapLinear ); + } + + this.gl.bindTexture(this.gl.TEXTURE_2D, this._texture); + // this.gl.texImage2D(this.gl.TEXTURE_2D, 0, this.format, this.width, this.height, 0, this.format, this.type, new Uint8Array( new Array(this.width * this.height * 4) )); + + if (this.type == this.gl.FLOAT) { + this.gl.texImage2D(this.gl.TEXTURE_2D, 0, this.format, this.width, this.height, 0, this.format, this.type, new Float32Array( new Array(this.width * this.height * 4) )); + } + else if (this.isHalfFloat) { + this.gl.texImage2D(this.gl.TEXTURE_2D, 0, this.format, this.width, this.height, 0, this.format, this.type, null); + } + else { + this.gl.texImage2D(this.gl.TEXTURE_2D, 0, this.format, this.width, this.height, 0, this.format, this.type, new Uint8Array( new Array(this.width * this.height * 4) )); + } + + + if (this.options.depthTexture) { + this.depthTexture.resize(this.width, this.height); + // this.gl.bindTexture(this.gl.TEXTURE_2D, this._depthTexture); + // this.gl.texImage2D(this.gl.TEXTURE_2D, 0, this.gl.DEPTH_COMPONENT, this.width, this.height, 0, this.gl.DEPTH_COMPONENT, this.gl.UNSIGNED_SHORT, null); + } + + this.gl.bindFramebuffer( this.gl.FRAMEBUFFER, this.fbo ); + this.gl.framebufferTexture2D(this.gl.FRAMEBUFFER, this.gl.COLOR_ATTACHMENT0, this.gl.TEXTURE_2D, this._texture, 0); + + if (this.options.depthTexture) { + this.gl.framebufferTexture2D(this.gl.FRAMEBUFFER, this.gl.DEPTH_ATTACHMENT, this.gl.TEXTURE_2D, this.options.depthTexture._texture, 0); + } + else { + this.gl.bindRenderbuffer(this.gl.RENDERBUFFER, this.renderbuffer); + this.gl.renderbufferStorage(this.gl.RENDERBUFFER, this.gl.DEPTH_COMPONENT16, this.width, this.height); + this.gl.framebufferRenderbuffer(this.gl.FRAMEBUFFER, this.gl.DEPTH_ATTACHMENT, this.gl.RENDERBUFFER, this.renderbuffer); + } + + this.unbind(); + } + + bindFrame() { + this.gl.viewport( 0, 0, this.width, this.height ); + this.gl.bindFramebuffer(this.gl.FRAMEBUFFER, this.fbo); + if (!this.options.depthTexture) { + this.gl.bindRenderbuffer(this.gl.RENDERBUFFER, this.renderbuffer); + } + else { + this.gl.bindRenderbuffer(this.gl.RENDERBUFFER, this.renderbuffer); + this.gl.renderbufferStorage(this.gl.RENDERBUFFER, this.gl.DEPTH_COMPONENT16, this.width, this.height); + this.gl.framebufferRenderbuffer(this.gl.FRAMEBUFFER, this.gl.DEPTH_ATTACHMENT, this.gl.RENDERBUFFER, this.renderbuffer); + } + this.clear(); + } + + bind(unit) { + if (unit !== void 0) { + this.gl.activeTexture( this.gl.TEXTURE0 + (0|unit) ); + } + // else { + // this.gl.activeTexture( this.gl.TEXTURE0 ); + // } + this.gl.bindTexture(this.gl.TEXTURE_2D, this._texture); + } + + unbind() { + this.gl.bindTexture(this.gl.TEXTURE_2D, null); + this.gl.bindFramebuffer(this.gl.FRAMEBUFFER, null); + if (!this.options.depthTexture) { + this.gl.bindRenderbuffer(this.gl.RENDERBUFFER, null); + } + } + + clear(color, depth, stencil) { + var bits = 0; + if ( color === void 0 || color ) bits |= this.gl.COLOR_BUFFER_BIT; + if ( depth === void 0 || depth ) bits |= this.gl.DEPTH_BUFFER_BIT; + if ( stencil === void 0 || stencil ) bits |= this.gl.STENCIL_BUFFER_BIT; + this.gl.clear( bits ); + } + + dispose() { + this.gl.deleteFramebuffer( this.fbo ); + this.fbo = null; + this.gl = null; + } + +} + + +export default FrameBuffer; diff --git a/src/globe/beam/FrameBuffer.new.js b/src/globe/beam/FrameBuffer.new.js new file mode 100755 index 0000000..47002fd --- /dev/null +++ b/src/globe/beam/FrameBuffer.new.js @@ -0,0 +1,74 @@ +import Texture from './Texture'; + +class FrameBuffer extends Texture { + + constructor ( gl, options ) { + + super(gl, options); + + this.fbo = this.gl.createFramebuffer(); + this.renderbuffer = this.gl.createRenderbuffer(); + + this.gl.bindFramebuffer( this.gl.FRAMEBUFFER, this.fbo ); + this.gl.framebufferTexture2D(this.gl.FRAMEBUFFER, this.gl.COLOR_ATTACHMENT0, this.gl.TEXTURE_2D, this._texture, 0); + + this.gl.bindRenderbuffer(this.gl.RENDERBUFFER, this.renderbuffer); + this.gl.renderbufferStorage(this.gl.RENDERBUFFER, this.gl.DEPTH_COMPONENT16, this.width, this.height); + this.gl.framebufferRenderbuffer(this.gl.FRAMEBUFFER, this.gl.DEPTH_ATTACHMENT, this.gl.RENDERBUFFER, this.renderbuffer); + + this.unbind(); + + } + + resize( w, h ){ + + if( this.width !== w || this.height !== h ) { + this.width = w|0; + this.height = h|0; + } + + this.gl.bindTexture(this.gl.TEXTURE_2D, this._texture); + this.gl.texImage2D(this.gl.TEXTURE_2D, 0, this.format, this.width, this.height, 0, this.format, this.type, null); + // this.gl.framebufferTexture2D( this.gl.FRAMEBUFFER, this.gl.COLOR_ATTACHMENT0, this.gl.TEXTURE_2D, this._texture, 0 ); + + this.gl.bindFramebuffer( this.gl.FRAMEBUFFER, this.fbo ); + this.gl.framebufferTexture2D(this.gl.FRAMEBUFFER, this.gl.COLOR_ATTACHMENT0, this.gl.TEXTURE_2D, this._texture, 0); + + this.gl.bindRenderbuffer(this.gl.RENDERBUFFER, this.renderbuffer); + this.gl.renderbufferStorage(this.gl.RENDERBUFFER, this.gl.DEPTH_COMPONENT16, this.width, this.height); + this.gl.framebufferRenderbuffer(this.gl.FRAMEBUFFER, this.gl.DEPTH_ATTACHMENT, this.gl.RENDERBUFFER, this.renderbuffer); + + this.unbind(); + + } + + bindFrame() { + this.gl.viewport( 0, 0, this.width, this.height ); + this.gl.bindRenderbuffer(this.gl.RENDERBUFFER, this.renderbuffer); + this.gl.bindFramebuffer(this.gl.FRAMEBUFFER, this.fbo); + this.clear(); + } + + unbind() { + this.gl.bindTexture(this.gl.TEXTURE_2D, null); + this.gl.bindRenderbuffer(this.gl.RENDERBUFFER, null); + this.gl.bindFramebuffer(this.gl.FRAMEBUFFER, null); + } + + clear(color, depth, stencil) { + var bits = 0; + if ( color === void 0 || color ) bits |= this.gl.COLOR_BUFFER_BIT; + if ( depth === void 0 || depth ) bits |= this.gl.DEPTH_BUFFER_BIT; + if ( stencil === void 0 || stencil ) bits |= this.gl.STENCIL_BUFFER_BIT; + this.gl.clear( bits ); + } + + dispose() { + this.gl.deleteFramebuffer( this.fbo ); + this.fbo = null; + this.gl = null; + } + +} + +export default FrameBuffer; diff --git a/src/globe/beam/GeometryBuffer.js b/src/globe/beam/GeometryBuffer.js new file mode 100755 index 0000000..9c5b718 --- /dev/null +++ b/src/globe/beam/GeometryBuffer.js @@ -0,0 +1,30 @@ +import ArrayBuffer from './ArrayBuffer'; + +class GeometryBuffer { + + constructor(gl, size) { + + if (!gl) { + return; + } + + this.gl = gl; + this.attributes = {} + this.length = size || 0; + + // this.vertices = []; + // this.addAttribute( 'index', new Uint16Array( this.indices ), 1 ); + // this.addAttribute( 'position', new Float32Array( this.vertices ), 3 ); + // this.addAttribute( 'normal', new Float32Array( this.normals ), 3 ); + // this.addAttribute( 'uv', new Float32Array( this.uvs ), 2 ); + + } + + addAttribute(attribName, data, size, geometry) { + this.attributes[attribName] = new ArrayBuffer(this.gl, data, size, attribName === 'index', geometry);//true=use element array buffer + } + +} + + +export default GeometryBuffer; \ No newline at end of file diff --git a/src/globe/beam/HDRTexture.js b/src/globe/beam/HDRTexture.js new file mode 100755 index 0000000..d843a44 --- /dev/null +++ b/src/globe/beam/HDRTexture.js @@ -0,0 +1,207 @@ +import uuid from './utils/uuid'; +import isPowerOf2 from './utils/isPowerOf2'; +import RGBEParser from './RGBEParser'; + + +import parseHDR from 'parse-hdr'; + + +function toArrayBuffer (buffer) { + var ab = new ArrayBuffer(buffer.length) + var view = new Uint8Array(ab) + for (var i = 0; i < buffer.length; ++i) { + view[i] = buffer[i] + } + return ab +} + +function BinaryLoad(){ + // this is just a helper class to ease BinaryLoad calls + var _this = this; + this.xmlhttp = new XMLHttpRequest(); + this.get = function(url, callback){ + _this.xmlhttp.onreadystatechange = function(){ + if(_this.xmlhttp.readyState === 4){ + callback(_this.xmlhttp.response, _this.xmlhttp.status); + } + }; + _this.xmlhttp.open('GET', url, true); + _this.xmlhttp.responseType = 'arraybuffer' + _this.xmlhttp.send(); + } +}; + + +function RGBEByteToRGBFloat( sourceArray, sourceOffset, destArray, destOffset ) { + var e = sourceArray[ sourceOffset + 3 ]; + var scale = Math.pow( 2.0, e - 128.0 ) / 255.0; + destArray[ destOffset + 0 ] = sourceArray[ sourceOffset + 0 ] * scale; + destArray[ destOffset + 1 ] = sourceArray[ sourceOffset + 1 ] * scale; + destArray[ destOffset + 2 ] = sourceArray[ sourceOffset + 2 ] * scale; +}; + +var RGBEByteToRGBHalf = ( function () { + // Source: http://gamedev.stackexchange.com/questions/17326/conversion-of-a-number-from-single-precision-floating-point-representation-to-a/17410#17410 + var floatView = new Float32Array( 1 ); + var int32View = new Int32Array( floatView.buffer ); + /* This method is faster than the OpenEXR implementation (very often + * used, eg. in Ogre), with the additional benefit of rounding, inspired + * by James Tursa?s half-precision code. */ + function toHalf( val ) { + floatView[ 0 ] = val; + var x = int32View[ 0 ]; + var bits = ( x >> 16 ) & 0x8000; /* Get the sign */ + var m = ( x >> 12 ) & 0x07ff; /* Keep one extra bit for rounding */ + var e = ( x >> 23 ) & 0xff; /* Using int is faster here */ + /* If zero, or denormal, or exponent underflows too much for a denormal + * half, return signed zero. */ + if ( e < 103 ) return bits; + /* If NaN, return NaN. If Inf or exponent overflow, return Inf. */ + if ( e > 142 ) { + bits |= 0x7c00; + /* If exponent was 0xff and one mantissa bit was set, it means NaN, + * not Inf, so make sure we set one mantissa bit too. */ + bits |= ( ( e == 255 ) ? 0 : 1 ) && ( x & 0x007fffff ); + return bits; + } + /* If exponent underflows but not too much, return a denormal */ + if ( e < 113 ) { + m |= 0x0800; + /* Extra rounding may overflow and set mantissa to 0 and exponent + * to 1, which is OK. */ + bits |= ( m >> ( 114 - e ) ) + ( ( m >> ( 113 - e ) ) & 1 ); + return bits; + + } + bits |= ( ( e - 112 ) << 10 ) | ( m >> 1 ); + /* Extra rounding. An overflow will set mantissa to 0 and increment + * the exponent, which is OK. */ + bits += m & 1; + return bits; + } + return function ( sourceArray, sourceOffset, destArray, destOffset ) { + var e = sourceArray[ sourceOffset + 3 ]; + var scale = Math.pow( 2.0, e - 128.0 ) / 255.0; + destArray[ destOffset + 0 ] = toHalf( sourceArray[ sourceOffset + 0 ] * scale ); + destArray[ destOffset + 1 ] = toHalf( sourceArray[ sourceOffset + 1 ] * scale ); + destArray[ destOffset + 2 ] = toHalf( sourceArray[ sourceOffset + 2 ] * scale ); + + }; +})(); + + + +class HDRTexture { + + constructor(gl, options) { + + options = Object.assign({}, { + format: gl.RGBA, + type: gl.UNSIGNED_BYTE, + width: 1, + height: 1, + linear: false, + mipmap: false, + miplinear: false, + wrapS: gl.CLAMP_TO_EDGE, + wrapT: gl.CLAMP_TO_EDGE, + url: null, + onReady:()=>{} + }, options); + + this.options = options + + this._uid = uuid();//debug purpose + this.gl = gl; + this.width = options.width; + this.height = options.height; + this.format = options.format; + this.type = options.type; + + var floatTextures = gl.getExtension('OES_texture_float'); + var floatTextureLinearFiltering = gl.getExtension('OES_texture_float_linear'); + + if (!floatTextures) { + throw('trying to create a FrameBuffer of with gl.FLOAT type but there\s no floating point texture support'); + return; + } + + this._texture = this.gl.createTexture(); + gl.bindTexture( gl.TEXTURE_2D, this._texture); + gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE); + gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE); + gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.NEAREST); + gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.NEAREST); + gl.texImage2D(gl.TEXTURE_2D, 0, this.options.format, this.width, this.height, 0, this.options.format, this.gl.UNSIGNED_BYTE, new Uint8Array([0, 0, 0, 255])); + gl.bindTexture( gl.TEXTURE_2D, null); + + if (this.options.url) { + this.load(this.options.url) + } + } + + load(url) { + console.log("HDRTexture.load", url) + new BinaryLoad().get(url, (data, status)=>{ + + if (status === 200) { + // var arrBuffer = toArrayBuffer(data); + var texData = RGBEParser(data); + // if ( this.options.type === this.gl.FLOAT ) { + // var numElements = ( texData.data.length / 4 ) * 3; + // var floatdata = new Float32Array( numElements ); + // for ( var j = 0; j < numElements; j ++ ) { + // RGBEByteToRGBFloat( texData.data, j * 4, floatdata, j * 3 ); + // } + // texData.data = floatdata; + // } else if ( this.options.type === this.gl.HALF_FLOAT ) { + // var numElements = ( texData.data.length / 4 ) * 3; + // var halfdata = new Uint16Array( numElements ); + // for ( var j = 0; j < numElements; j ++ ) { + // RGBEByteToRGBHalf( texData.data, j * 4, halfdata, j * 3 ); + // } + // texData.data = halfdata; + // } + this.gl.bindTexture( this.gl.TEXTURE_2D, this._texture); + this.gl.texParameteri(this.gl.TEXTURE_2D, this.gl.TEXTURE_WRAP_S, this.gl.CLAMP_TO_EDGE); + this.gl.texParameteri(this.gl.TEXTURE_2D, this.gl.TEXTURE_WRAP_T, this.gl.CLAMP_TO_EDGE); + this.gl.texParameteri(this.gl.TEXTURE_2D, this.gl.TEXTURE_MIN_FILTER, this.gl.NEAREST); + this.gl.texParameteri(this.gl.TEXTURE_2D, this.gl.TEXTURE_MAG_FILTER, this.gl.NEAREST); + this.width = texData.width + this.height = texData.height + this.gl.texImage2D(this.gl.TEXTURE_2D, 0, this.options.format, texData.width, texData.height, 0, this.options.format, this.options.type, texData.data); + this.gl.bindTexture( this.gl.TEXTURE_2D, null); + + this.options.onReady() + + } + else { + error = true; + console.error('An error has occurred and the HDR "' + url + '" could not be downloaded.'); + } + }) + } + + bind(unit) { + if (!this.gl) { + return; + } + //unit is sent by the Program and defined by the unfirom order in the shaders; + if (unit !== void 0) { + this.gl.activeTexture( this.gl.TEXTURE0 + (0|unit) ); + } + this.gl.bindTexture(this.gl.TEXTURE_2D, this._texture); + } + + delete() { + if (this.gl) { + this.gl.deleteTexture( this._texture ); + } + this._texture = null; + this.gl = null; + } + + +} + +export default HDRTexture; diff --git a/src/globe/beam/JSONGeometryBuffer.js b/src/globe/beam/JSONGeometryBuffer.js new file mode 100644 index 0000000..d83b7ce --- /dev/null +++ b/src/globe/beam/JSONGeometryBuffer.js @@ -0,0 +1,84 @@ +import {GeometryBuffer} from 'beam'; +import {ArrayBuffer} from 'beam'; + +class Ajax { + constructor() { + this.xmlhttp = new XMLHttpRequest(); + this.get = (url, callback)=>{ + this.xmlhttp.onreadystatechange = ()=>{ + if(this.xmlhttp.readyState === 4){ + callback(this.xmlhttp.responseText, this.xmlhttp.status); + } + }; + this.xmlhttp.open('GET', url, true); + this.xmlhttp.send(); + } + } +}; + + + +class JSONGeometryBuffer extends GeometryBuffer { + constructor(gl, options) { + super(gl, 4.); + this.gl = gl; + options = Object.assign({},{ + src: null, + onLoaded: ()=>{} + }, options); + this.options = options; + // buffers + this.indices = []; + this.vertices = []; + this.normals = []; + this.uvs = []; + // build geometry + this.length = 0; + this.addAttribute( 'index', new Uint16Array( this.indices ), 1 ); + this.addAttribute( 'position', new Float32Array( this.vertices ), 3 ); + this.addAttribute( 'normal', new Float32Array( this.normals ), 3 ); + this.addAttribute( 'uv', new Float32Array( this.uvs ), 2 ); + new Ajax().get(options.src, (data, status)=>{ + if (status !== 200) { + console.error('An error has occurred while download JSON: ' + this.props.src); + throw ''; + } + else { + this._onDataLoaded(JSON.parse(data)) + } + }); + } + + _onDataLoaded(meshes) { + this.attributes = {} + this.indices = meshes.indices + this.vertices = meshes.vertices + this.normals = meshes.vertexNormals + this.uvs = meshes.textures + let needsUvs, needsNormals; + if (this.uvs.length == 0) { + needsUvs = true; + } + if (this.normals.length == 0) { + needsNormals = true; + } + for (let i=0; i{ + image.onload = null; + image.onerror = null; + this.cache[url] = image; + callback(image); + } + + image.onerror = ()=>{ + image.onload = null; + image.onerror = null; + console.warn('Cannot load image :' + url); + } + + image.src = url; + + } + +} \ No newline at end of file diff --git a/src/globe/beam/Material.js b/src/globe/beam/Material.js new file mode 100755 index 0000000..4274614 --- /dev/null +++ b/src/globe/beam/Material.js @@ -0,0 +1,54 @@ +import Program from './Program'; +import vertexShader from './shaders/default-vs.glsl'; +import fragmentShader from './shaders/mesh-fs.glsl'; + +class Material extends Program { + + constructor( gl, options ){ + + options = Object.assign({}, { + vertexShader: vertexShader, + fragmentShader: fragmentShader, + map: null, + }, options); + + options.uniforms = Object.assign({}, { + color: [1,1,1], + alpha: 1 + }, options.uniforms); + + options.defines = Object.assign({}, { + USE_MAP: false + }, options.defines); + + super(gl, options); + + if (!gl) { + return; + } + + Object.defineProperty(this, 'map', { + set: (value) => { + if (value) { + this.defines.USE_MAP = true; + this.compile(); + if (this.uniforms.map) { + this.uniforms.map.value = value; + } + } + else { + this.defines.USE_MAP = false; + this.compile(); + } + } + }); + + this.map = options.map; + + } + + + +} + +export default Material; \ No newline at end of file diff --git a/src/globe/beam/Mesh.js b/src/globe/beam/Mesh.js new file mode 100755 index 0000000..8f08e46 --- /dev/null +++ b/src/globe/beam/Mesh.js @@ -0,0 +1,90 @@ +import Container from './Container'; +import * as mat4 from './glMatrix/mat4'; + +class Mesh extends Container { + + constructor(options) { + super(); + this.material = null; + this.geometry = null; + this.options = options ||Ā {}; + this._viewMatrix = mat4.create() + this._invViewMatrix = mat4.create() + this._modelViewMatrix = mat4.create() + this._normalMatrix = mat4.create() + } + + render(camera, options={}) { + + super.render( camera, options ); + + let material = options.overrideMaterial || this.material; + + if (camera && material && + this.geometry && //TODO: check for geometry.length + this.visible) { + + if (this.options.beforeRender) { + this.options.beforeRender() + } + // setTimeout(()=>{ + mat4.invert(this._viewMatrix, camera.worldMatrix); + mat4.multiply(this._modelViewMatrix, this._viewMatrix, this.worldMatrix); + + if (material.uniforms['uInverseViewMatrix'] !== void 0) { + mat4.copy(this._invViewMatrix, camera.worldMatrix); + mat4.invert(this._invViewMatrix, this._invViewMatrix); + material.uniforms['uInverseViewMatrix'].value = camera.worldMatrix; + } + + if (material.uniforms['uCameraPosition'] !== void 0) { + material.uniforms['uCameraPosition'].value = camera.position; + } + if (material.uniforms['uVMatrix'] !== void 0) { + material.uniforms['uVMatrix'].value = this._viewMatrix; + } + if (material.uniforms['uNormalMatrix'] !== void 0) { + mat4.multiply( this._normalMatrix, this._rotationMat4, this.parent._rotationMat4); + material.uniforms['uNormalMatrix'].value = this._normalMatrix + } + if (material.uniforms['uMMatrix'] !== void 0) { + material.uniforms['uMMatrix'].value = this.worldMatrix; + // console.log('MANUALLY ASSIGN ', this.matrix, this.name) + // console.log('setMM', this.name, this.matrix[0], this.matrix[1], this.matrix[2], this.matrix[3]) + } + if (material.uniforms['uMVMatrix'] !== void 0) { + material.uniforms['uMVMatrix'].value = this._modelViewMatrix; + } + + if (material.uniforms['uPMatrix'] !== void 0) { + material.uniforms['uPMatrix'].value = camera.projectionMatrix; + } + + for (let u in options.uniforms) { + if (material.uniforms[ u ] !== void 0) { + material.uniforms[ u ].value = options.uniforms[u]; + } + } + + let needsCompile = false; + for (let k in options.defines) { + if (material.defines[ k ] !== options.defines[ k ]) { + material.defines[ k ] = options.defines[ k ]; + needsCompile = true; + } + } + + if (needsCompile) { + material.compile(); + } + + material.draw( this.geometry ); + // }) + + } + + } + +} + +export default Mesh; \ No newline at end of file diff --git a/src/globe/beam/ObjGeometryBuffer.js b/src/globe/beam/ObjGeometryBuffer.js new file mode 100755 index 0000000..1500890 --- /dev/null +++ b/src/globe/beam/ObjGeometryBuffer.js @@ -0,0 +1,68 @@ +import {GeometryBuffer} from 'beam'; +import {vec3} from 'beam'; +import OBJ from "./webgl-obj-loader" +import {ArrayBuffer} from 'beam'; + +class ObjGeometryBuffer extends GeometryBuffer { + constructor(gl, options) { + super(gl, 4.); + this.gl = gl; + options = Object.assign({},{ + src: null, + onLoaded: ()=>{} + }, options); + this.options = options; + // buffers + this.indices = []; + this.vertices = []; + this.normals = []; + this.uvs = []; + // build geometry + this.length = 0; + this.addAttribute( 'index', new Uint16Array( this.indices ), 1 ); + this.addAttribute( 'position', new Float32Array( this.vertices ), 3 ); + this.addAttribute( 'normal', new Float32Array( this.normals ), 3 ); + this.addAttribute( 'uv', new Float32Array( this.uvs ), 2 ); + this.onObjLoaded = this.onObjLoaded.bind(this); + if (options.lod) { + OBJ.downloadMeshes(options.lod, this.onObjLoaded) + } + else { + OBJ.downloadMeshes([options.src], this.onObjLoaded); + } + } + + onObjLoaded(meshes) { + + this.attributes = {} + this.indices = meshes[0].indices + this.vertices = meshes[0].vertices + this.normals = meshes[0].vertexNormals + this.uvs = meshes[0].textures + let needsUvs, needsNormals; + if (this.uvs.length == 0) { + needsUvs = true; + } + if (this.normals.length == 0) { + needsNormals = true; + } + for (let i=0; i 3){ + index = 0; + particleIndex++; + } + + } + + for (let m=0,n=0;n> 0; + var gridY = this.heightSegments >> 0; + var gridX1 = gridX + 1; + var gridY1 = gridY + 1; + var segment_width = this.width / gridX; + var segment_height = this.height / gridY; + + var ix, iy; + + // generate vertices, normals and uvs + for ( iy = 0; iy < gridY1; iy ++ ) { + var y = iy * segment_height - height_half; + for ( ix = 0; ix < gridX1; ix ++ ) { + var x = ix * segment_width - width_half; + this.vertices.push( x, - y, 0 ); + this.normals.push( 0, 0, 1 ); + this.uvs.push( ix / gridX, 1 - ( iy / gridY ) ); + this.colors.push( 1, 1, 1 ); + } + } + + // indices + for ( iy = 0; iy < gridY; iy ++ ) { + for ( ix = 0; ix < gridX; ix ++ ) { + var a = ix + gridX1 * iy; + var b = ix + gridX1 * ( iy + 1 ); + var c = ( ix + 1 ) + gridX1 * ( iy + 1 ); + var d = ( ix + 1 ) + gridX1 * iy; + // faces + this.indices.push( a, b, d ); + this.indices.push( b, c, d ); + } + } + + this.length = this.vertices.length/3; + + } + + +} + +export default PlaneGeometryBuffer; \ No newline at end of file diff --git a/src/globe/beam/Program.js b/src/globe/beam/Program.js new file mode 100755 index 0000000..559d653 --- /dev/null +++ b/src/globe/beam/Program.js @@ -0,0 +1,448 @@ +import UNIFORM_TYPE from './uniformTypes'; +import defaultVertexShader from './shaders/default-vs.glsl'; +import defaultFragmentShader from './shaders/default-fs.glsl'; +import uuid from './utils/uuid'; + +const TEXTURE_2D = 35678 +const TEXTURE_CUBE_MAP = 35680; + +function addLineNumbers( string ) { + var lines = string.split( '\n' ); + for ( var i = 0; i < lines.length; i ++ ) { + lines[ i ] = ( i + 1 ) + ': ' + lines[ i ]; + } + return lines.join( '\n' ); +} + +function compileShader( gl, shader, code ){ + gl.shaderSource( shader, code ); + gl.compileShader( shader ); + if (!gl.getShaderParameter(shader, gl.COMPILE_STATUS)) { + console.error('Shader cannot compile: \n' + gl.getShaderInfoLog(shader) || "" ); + console.warn(addLineNumbers(code)); + return false; + } + return true; +} + + + +var _lastUsedDepthTest = null +var _lastUsedGeometry = null + + +class Program { + + constructor(gl, options={}) { + + this._uuid = uuid(); + + if (!gl) { + return; + } + + options = Object.assign({}, { + vertexShader: defaultVertexShader, + fragmentShader: defaultFragmentShader, + defines: {}, + extentions: {}, + uniforms: {}, + type: gl.TRIANGLES + }, options); + + this.options = options; + + this._vertexShaderSource = options.vertexShader; + this._fragmentShaderSource = options.fragmentShader; + + this.gl = gl; + this._program = gl.createProgram(); + this.vertexShader = gl.createShader( gl.VERTEX_SHADER ); + this.fragmentShader = gl.createShader( gl.FRAGMENT_SHADER ); + + gl.attachShader(this._program, this.vertexShader); + gl.attachShader(this._program, this.fragmentShader); + + this.type = options.type; + this.attributes = {}; + this.defines = options.defines; + this.extentions = options.extentions; + + this._textureUnit = 0; + + this.depthTest = options.depthTest !== void 0 ? options.depthTest : true; + this.blend = options.blend !== void 0 ? options.blend : false; + this.blendEquation = options.blendEquation !== void 0 ? options.blendEquation : this.gl.FUNC_ADD; + this.blendSrc = options.blendSrc !== void 0 ? options.blendSrc : this.gl.SRC_ALPHA; + this.blendDst = options.blendDst !== void 0 ? options.blendDst : this.gl.ONE_MINUS_SRC_ALPHA; + this.blendSrcRGB = options.blendSrcRGB !== void 0 ? options.blendSrcRGB : this.gl.SRC_ALPHA; + this.blendDstRGB = options.blendDstRGB !== void 0 ? options.blendDstRGB : this.gl.ONE_MINUS_SRC_ALPHA; + this.blendSrcAlpha = options.blendSrcAlpha !== void 0 ? options.blendSrcAlpha : this.gl.ONE; + this.blendDstAlpha = options.blendDstAlpha !== void 0 ? options.blendDstAlpha : this.gl.ONE_MINUS_SRC_ALPHA; + + this.wireframe = options.wireframe !== void 0 ? options.wireframe : false; + + this.uniforms = {}; + + this._userDefinedUniforms = options.uniforms; + this.compile(); + + } + + compile() { + + if (!this.gl) { + return; + } + + if (this.isCompiling) { + return; + } + + this.isCompiling = true; + + var defines = ''; + for (var d in this.defines) { + if (this.defines[d]) { + defines += '#define '+d+' '+this.defines[d]+'\n'; + } + } + + if( !( compileShader( this.gl, this.vertexShader, defines + this._vertexShaderSource ) && + compileShader( this.gl, this.fragmentShader, defines + this._fragmentShaderSource ) ) ) { + console.warn('compile error') + return false; + } + + this.gl.linkProgram(this._program); + + if (!this.gl.getProgramParameter(this._program, this.gl.LINK_STATUS)) { + console.error("Cannot link program: \n" + this.gl.getProgramInfoLog(this._program) || ""); + console.warn("VERTEX_SHADER:\n"+addLineNumbers(this._vertexShaderSource) + +"\n\nFRAGMENT_SHADER:\n"+addLineNumbers(this._fragmentShaderSource)); + } + + this.gl.useProgram(this._program); + + this._retrieveUniformsFromShader(); + + this.isCompiling = false; + + } + + _retrieveUniformsFromShader() { + + + +//debug +let isMMatrix = false; + + this._savedUniforms = {}; + for (let k in this.uniforms) { + this._savedUniforms[k] = { + value: this.uniforms[k].value + } + } + + this.uniforms = {}; + this._textureUnit = 0; + + var numUniforms = this.gl.getProgramParameter( this._program, this.gl.ACTIVE_UNIFORMS ); + + for (let i = 0; i < numUniforms; ++i) { + + var uniform = this.gl.getActiveUniform( this._program, i ); + + if( uniform === null ){ + this.gl.getError(); + continue; + } + + let name = uniform.name; + + + + let isArray = false;//is uniform array ?(ex: 3fv, 4fv...) + + // tltr; we want 'myUniform[0]' to become 'myUniform' + // if array uniform, replace the retrieved name as it includes the first index acces + if (/\[.*\]/.test(name) ) { + isArray = true; + name = name.replace(/\[.*\]/,''); + } + + + if (this.uniforms[ name ] !== void 0) { + this.uniforms[ name ].location = this.gl.getUniformLocation( this._program, name ); + this.uniforms[ name ].type = uniform.type; + + } + else { + + this.uniforms[ name ] = { + isArray: isArray, + location: this.gl.getUniformLocation( this._program, name ), + type: uniform.type, + value: null, + size: uniform.size + } + + //set texture unit + if (uniform.type === TEXTURE_2D || uniform.type === TEXTURE_CUBE_MAP) { + this.uniforms[ name ].unit = this._textureUnit; + this._textureUnit++; + } + + } + + } + + + +let isEnd = false; + //merge user defined uniforms + for (let u in this._savedUniforms) { + + + + if (this.uniforms[u] !== void 0){ + if (this._savedUniforms[u].value !== void 0 + && this._savedUniforms[u].value !== null) { + + + this.uniforms[u].value = this._savedUniforms[u].value; + } + } + else { + + } + + } + + + for (let u in this._userDefinedUniforms) { + if (this.uniforms[u] !== void 0 + && this._userDefinedUniforms[u] !== void 0 + && this._userDefinedUniforms[u] !== null) { + this.uniforms[u].value = this._userDefinedUniforms[u]; + } + } + + + var numAttributes = this.gl.getProgramParameter( this._program, this.gl.ACTIVE_ATTRIBUTES ); + + for (let i = 0; i < numAttributes; ++i) { + + var attribute = this.gl.getActiveAttrib( this._program, i ); + + if( attribute === null ){ + this.gl.getError(); + continue; + } + + this.attributes[ attribute.name ] = { + location: this.gl.getAttribLocation( this._program, attribute.name ), + type: attribute.type + } + + //the attribute is only enabled when the buffer is binded + //(so it's enabled by the Program that will use the buffer) + //this way we make sure that any enabled attribute has some data not to trigger an error + //see http://www.mjbshaw.com/2013/03/webgl-fixing-invalidoperation.html + // this.gl.enableVertexAttribArray( this.attributes[attribute.name].location ); + + } + + + } + + dispose() { + + } + + use () { + if (!this.gl) { + return; + } + + + this.gl.useProgram(this._program); + } + + attribPointer(attributes, geometry) { + + if (!this.gl) { + return; + } + + for (var attr in this.attributes) { + if (attributes[attr] !== void 0) { + attributes[attr].bind(); + this.gl.vertexAttribPointer( this.attributes[attr].location, attributes[attr].size, attributes[attr].type, false, 0, 0); + this.gl.enableVertexAttribArray( this.attributes[attr].location ); + } + } + } + + draw(geometry) { + + if (!this.gl) { + return; + } + + + this.gl.useProgram(this._program); + + //todo add a flah on attribute to check if they changed and thus needs to be binded again + //todo check the currently used program to know if it need some buffer bindings + // if (geometry !== _lastUsedGeometry) { + //TODO: check if geometry has changed + this.attribPointer(geometry.attributes, geometry); + // _lastUsedGeometry = geometry; + // } + + // if (this.depthTest !== _lastUsedDepthTest) { + this.gl[ this.depthTest ? 'enable' : 'disable' ](this.gl.DEPTH_TEST); + // _lastUsedDepthTest = this.depthTest; + // } + + if (this.blend) { + + // this.gl.disable(this.gl.DEPTH_TEST); + // this.gl[ this.depthTest ? 'enable' : 'disable' ](this.gl.DEPTH_TEST); + + if (this.depthTest) { + this.gl.depthFunc( this.gl.LESS ); + } + + + this.gl.blendEquation(this.blendEquation); + this.gl.blendFuncSeparate(this.blendSrcRGB, this.blendDstRGB, this.blendSrcAlpha, this.blendDstAlpha); + // this.gl.blendFunc(this.blendSrc,this.blendDst); + this.gl.enable(this.gl.BLEND); + + } + else { + this.gl.disable(this.gl.BLEND); + // this.gl[ this.depthTest ? 'enable' : 'disable' ](this.gl.DEPTH_TEST); + if (this.depthTest) { + this.gl.depthFunc( this.gl.LESS ); + } + } + + + + + + var keys = Object.keys(this.uniforms); + + for (var i=0,l=keys.length; i "3fv" + if (this.uniforms[ uniformName ].isArray) { + type += 'v'; + } + + if (this.uniforms[ uniformName ].value !== null) { + + if (type == '2f') { + this.gl['uniform' + type ](this.uniforms[ uniformName ].location, this.uniforms[ uniformName ].value[0], this.uniforms[ uniformName ].value[1]); + + // drawnUniforms2f.push(uniformName); + } + else if (type == '3f') { + this.gl['uniform' + type ](this.uniforms[ uniformName ].location, this.uniforms[ uniformName ].value[0], this.uniforms[ uniformName ].value[1], this.uniforms[ uniformName ].value[2]); + + // drawnUniforms3f.push(uniformName); + } + else if (type == '4f') { + this.gl['uniform' + type ](this.uniforms[ uniformName ].location, this.uniforms[ uniformName ].value[0], this.uniforms[ uniformName ].value[1], this.uniforms[ uniformName ].value[2], this.uniforms[ uniformName ].value[3]); + + // drawnUniforms4f.push(uniformName); + } + else { + + // drawnUniforms1f.push(uniformName); + this.gl['uniform' + type ](this.uniforms[ uniformName ].location, this.uniforms[ uniformName ].value); + } + + } + + } + //break; + } + + } + + if ( this.type !== this.gl.POINTS && + geometry.attributes['index'] ) { + geometry.attributes['index'].bind() + this.gl.drawElements(this.wireframe ? this.gl.LINE_STRIP : this.type, geometry.attributes['index'].length, this.gl.UNSIGNED_SHORT, 0); + } + else { + this.gl.drawArrays(this.wireframe ? this.gl.LINE_STRIP : this.type, 0, geometry.length); + } + + + } + +} + + +// var drawnUniformsTextures = [] +// var drawnUniforms1f = [] +// var drawnUniforms2f = [] +// var drawnUniforms3f = [] +// var drawnUniforms4f = [] + +// function flushUniforms() { +// console.log('1f: ' + drawnUniforms1f.length + '\n' + +// '2f: ' + drawnUniforms2f.length + '\n' + +// '3f: ' + drawnUniforms3f.length + '\n' + +// '4f: ' + drawnUniforms4f.length + '\n' + +// 'tx: ' + drawnUniformsTextures.length + '\n' ); + +// drawnUniformsTextures = [] +// drawnUniforms1f = [] +// drawnUniforms2f = [] +// drawnUniforms3f = [] +// drawnUniforms4f = [] +// requestAnimationFrame(flushUniforms) +// } + +// flushUniforms(); + +export default Program; \ No newline at end of file diff --git a/src/globe/beam/RGBEParser.js b/src/globe/beam/RGBEParser.js new file mode 100644 index 0000000..9aa0232 --- /dev/null +++ b/src/globe/beam/RGBEParser.js @@ -0,0 +1,331 @@ + +// adapted from http://www.graphics.cornell.edu/~bjw/rgbe.html +export default function parse( buffer ) { + + var + /* return codes for rgbe routines */ + RGBE_RETURN_SUCCESS = 0, + RGBE_RETURN_FAILURE = - 1, + + /* default error routine. change this to change error handling */ + rgbe_read_error = 1, + rgbe_write_error = 2, + rgbe_format_error = 3, + rgbe_memory_error = 4, + + rgbe_error = function ( rgbe_error_code, msg ) { + switch ( rgbe_error_code ) { + case rgbe_read_error: console.error( "THREE.RGBELoader Read Error: " + ( msg || '' ) ); + break; + case rgbe_write_error: console.error( "THREE.RGBELoader Write Error: " + ( msg || '' ) ); + break; + case rgbe_format_error: console.error( "THREE.RGBELoader Bad File Format: " + ( msg || '' ) ); + break; + default: + case rgbe_memory_error: console.error( "THREE.RGBELoader: Error: " + ( msg || '' ) ); + + } + return RGBE_RETURN_FAILURE; + }, + + /* offsets to red, green, and blue components in a data (float) pixel */ + RGBE_DATA_RED = 0, + RGBE_DATA_GREEN = 1, + RGBE_DATA_BLUE = 2, + + /* number of floats per pixel, use 4 since stored in rgba image format */ + RGBE_DATA_SIZE = 4, + + /* flags indicating which fields in an rgbe_header_info are valid */ + RGBE_VALID_PROGRAMTYPE = 1, + RGBE_VALID_FORMAT = 2, + RGBE_VALID_DIMENSIONS = 4, + + NEWLINE = "\n", + + fgets = function ( buffer, lineLimit, consume ) { + + lineLimit = ! lineLimit ? 1024 : lineLimit; + var p = buffer.pos, + i = - 1, len = 0, s = '', chunkSize = 128, + chunk = String.fromCharCode.apply( null, new Uint16Array( buffer.subarray( p, p + chunkSize ) ) ) + ; + while ( ( 0 > ( i = chunk.indexOf( NEWLINE ) ) ) && ( len < lineLimit ) && ( p < buffer.byteLength ) ) { + + s += chunk; len += chunk.length; + p += chunkSize; + chunk += String.fromCharCode.apply( null, new Uint16Array( buffer.subarray( p, p + chunkSize ) ) ); + + } + + if ( - 1 < i ) { + + /*for (i=l-1; i>=0; i--) { + byteCode = m.charCodeAt(i); + if (byteCode > 0x7f && byteCode <= 0x7ff) byteLen++; + else if (byteCode > 0x7ff && byteCode <= 0xffff) byteLen += 2; + if (byteCode >= 0xDC00 && byteCode <= 0xDFFF) i--; //trail surrogate + }*/ + if ( false !== consume ) buffer.pos += len + i + 1; + return s + chunk.slice( 0, i ); + + } + return false; + + }, + + /* minimal header reading. modify if you want to parse more information */ + RGBE_ReadHeader = function ( buffer ) { + + var line, match, + + // regexes to parse header info fields + magic_token_re = /^#\?(\S+)$/, + gamma_re = /^\s*GAMMA\s*=\s*(\d+(\.\d+)?)\s*$/, + exposure_re = /^\s*EXPOSURE\s*=\s*(\d+(\.\d+)?)\s*$/, + format_re = /^\s*FORMAT=(\S+)\s*$/, + dimensions_re = /^\s*\-Y\s+(\d+)\s+\+X\s+(\d+)\s*$/, + + // RGBE format header struct + header = { + + valid: 0, /* indicate which fields are valid */ + + string: '', /* the actual header string */ + + comments: '', /* comments found in header */ + + programtype: 'RGBE', /* listed at beginning of file to identify it after "#?". defaults to "RGBE" */ + + format: '', /* RGBE format, default 32-bit_rle_rgbe */ + + gamma: 1.0, /* image has already been gamma corrected with given gamma. defaults to 1.0 (no correction) */ + + exposure: 1.0, /* a value of 1.0 in an image corresponds to watts/steradian/m^2. defaults to 1.0 */ + + width: 0, height: 0 /* image dimensions, width/height */ + + }; + + if ( buffer.pos >= buffer.byteLength || ! ( line = fgets( buffer ) ) ) { + + return rgbe_error( rgbe_read_error, "no header found" ); + + } + /* if you want to require the magic token then uncomment the next line */ + if ( ! ( match = line.match( magic_token_re ) ) ) { + + return rgbe_error( rgbe_format_error, "bad initial token" ); + + } + header.valid |= RGBE_VALID_PROGRAMTYPE; + header.programtype = match[ 1 ]; + header.string += line + "\n"; + + while ( true ) { + + line = fgets( buffer ); + if ( false === line ) break; + header.string += line + "\n"; + + if ( '#' === line.charAt( 0 ) ) { + + header.comments += line + "\n"; + continue; // comment line + + } + + if ( match = line.match( gamma_re ) ) { + + header.gamma = parseFloat( match[ 1 ], 10 ); + + } + if ( match = line.match( exposure_re ) ) { + + header.exposure = parseFloat( match[ 1 ], 10 ); + + } + if ( match = line.match( format_re ) ) { + + header.valid |= RGBE_VALID_FORMAT; + header.format = match[ 1 ];//'32-bit_rle_rgbe'; + + } + if ( match = line.match( dimensions_re ) ) { + + header.valid |= RGBE_VALID_DIMENSIONS; + header.height = parseInt( match[ 1 ], 10 ); + header.width = parseInt( match[ 2 ], 10 ); + + } + + if ( ( header.valid & RGBE_VALID_FORMAT ) && ( header.valid & RGBE_VALID_DIMENSIONS ) ) break; + + } + + if ( ! ( header.valid & RGBE_VALID_FORMAT ) ) { + + return rgbe_error( rgbe_format_error, "missing format specifier" ); + + } + if ( ! ( header.valid & RGBE_VALID_DIMENSIONS ) ) { + + return rgbe_error( rgbe_format_error, "missing image size specifier" ); + + } + + return header; + + }, + + RGBE_ReadPixels_RLE = function ( buffer, w, h ) { + + var data_rgba, offset, pos, count, byteValue, + scanline_buffer, ptr, ptr_end, i, l, off, isEncodedRun, + scanline_width = w, num_scanlines = h, rgbeStart + ; + + if ( + // run length encoding is not allowed so read flat + ( ( scanline_width < 8 ) || ( scanline_width > 0x7fff ) ) || + // this file is not run length encoded + ( ( 2 !== buffer[ 0 ] ) || ( 2 !== buffer[ 1 ] ) || ( buffer[ 2 ] & 0x80 ) ) + ) { + + // return the flat buffer + return new Uint8Array( buffer ); + + } + + if ( scanline_width !== ( ( buffer[ 2 ] << 8 ) | buffer[ 3 ] ) ) { + + return rgbe_error( rgbe_format_error, "wrong scanline width" ); + + } + + data_rgba = new Uint8Array( 4 * w * h ); + + if ( ! data_rgba || ! data_rgba.length ) { + + return rgbe_error( rgbe_memory_error, "unable to allocate buffer space" ); + + } + + offset = 0; pos = 0; ptr_end = 4 * scanline_width; + rgbeStart = new Uint8Array( 4 ); + scanline_buffer = new Uint8Array( ptr_end ); + + // read in each successive scanline + while ( ( num_scanlines > 0 ) && ( pos < buffer.byteLength ) ) { + + if ( pos + 4 > buffer.byteLength ) { + + return rgbe_error( rgbe_read_error ); + + } + + rgbeStart[ 0 ] = buffer[ pos ++ ]; + rgbeStart[ 1 ] = buffer[ pos ++ ]; + rgbeStart[ 2 ] = buffer[ pos ++ ]; + rgbeStart[ 3 ] = buffer[ pos ++ ]; + + if ( ( 2 != rgbeStart[ 0 ] ) || ( 2 != rgbeStart[ 1 ] ) || ( ( ( rgbeStart[ 2 ] << 8 ) | rgbeStart[ 3 ] ) != scanline_width ) ) { + + return rgbe_error( rgbe_format_error, "bad rgbe scanline format" ); + + } + + // read each of the four channels for the scanline into the buffer + // first red, then green, then blue, then exponent + ptr = 0; + while ( ( ptr < ptr_end ) && ( pos < buffer.byteLength ) ) { + + count = buffer[ pos ++ ]; + isEncodedRun = count > 128; + if ( isEncodedRun ) count -= 128; + + if ( ( 0 === count ) || ( ptr + count > ptr_end ) ) { + + return rgbe_error( rgbe_format_error, "bad scanline data" ); + + } + + if ( isEncodedRun ) { + + // a (encoded) run of the same value + byteValue = buffer[ pos ++ ]; + for ( i = 0; i < count; i ++ ) { + + scanline_buffer[ ptr ++ ] = byteValue; + + } + //ptr += count; + + } else { + + // a literal-run + scanline_buffer.set( buffer.subarray( pos, pos + count ), ptr ); + ptr += count; pos += count; + + } + + } + + + // now convert data from buffer into rgba + // first red, then green, then blue, then exponent (alpha) + l = scanline_width; //scanline_buffer.byteLength; + for ( i = 0; i < l; i ++ ) { + + off = 0; + data_rgba[ offset ] = scanline_buffer[ i + off ]; + off += scanline_width; //1; + data_rgba[ offset + 1 ] = scanline_buffer[ i + off ]; + off += scanline_width; //1; + data_rgba[ offset + 2 ] = scanline_buffer[ i + off ]; + off += scanline_width; //1; + data_rgba[ offset + 3 ] = scanline_buffer[ i + off ]; + offset += 4; + + } + + num_scanlines --; + + } + + return data_rgba; + + } + ; + + var byteArray = new Uint8Array( buffer ), + byteLength = byteArray.byteLength; + byteArray.pos = 0; + var rgbe_header_info = RGBE_ReadHeader( byteArray ); + + if ( RGBE_RETURN_FAILURE !== rgbe_header_info ) { + + var w = rgbe_header_info.width, + h = rgbe_header_info.height, + image_rgba_data = RGBE_ReadPixels_RLE( byteArray.subarray( byteArray.pos ), w, h ) + ; + if ( RGBE_RETURN_FAILURE !== image_rgba_data ) { + + return { + width: w, + height: h, + data: image_rgba_data, + header: rgbe_header_info.string, + gamma: rgbe_header_info.gamma, + exposure: rgbe_header_info.exposure, + format: 'RGBA', // handled as THREE.RGBAFormat in shaders + type: 'UnsignedByteType' + }; + + } + + } + return null; + +}; + diff --git a/src/globe/beam/Renderer.js b/src/globe/beam/Renderer.js new file mode 100755 index 0000000..71effdd --- /dev/null +++ b/src/globe/beam/Renderer.js @@ -0,0 +1,103 @@ + +class Renderer { + + constructor(options) { + + this.canvas = (options && options.canvas) || document.createElement('canvas'); + + this.canvas.style.transformOrigin = '0 0'; + + this.contextAttributes = Object.assign({},{ + alpha: false, + depth: true, + stencil: true, + antialias: false, + premultipliedAlpha: true, + preserveDrawingBuffer: false, + failIfMajorPerformanceCaveat: false, + }, (options || {}) ); + + this._pixelRatio = 1; + + this.gl = this.canvas.getContext("experimental-webgl", this.contextAttributes); + + this.handleContextLost = this.handleContextLost.bind(this); + this.handleContextRestored = this.handleContextRestored.bind(this); + this.canvas.addEventListener('webglcontextlost', this.handleContextLost, false); + this.canvas.addEventListener('webglcontextrestored', this.handleContextRestored, false); + + } + + handleContextLost(event){ + event.preventDefault(); + } + + handleContextRestored(){ + + } + + handleContextRestored() { + + } + + render(container, camera, frameBuffer, preventCameraUpdate) { + + if (!this.gl) { + return; + } + + if (!preventCameraUpdate) { + camera.update(); + } + + if (frameBuffer){ + frameBuffer.bindFrame(); + container.render( camera ); + frameBuffer.unbind(); + } + else{ + this.gl.viewport(0, 0, this._width* this._pixelRatio , this._height* this._pixelRatio ); + container.render( camera ); + } + + } + + resize(width, height) { + if (!this.gl) { + return; + } + this._width = width; + this._height = height; + this.canvas.width = this._width * this._pixelRatio; + this.canvas.height = this._height * this._pixelRatio; + this.canvas.style.transform = 'scale('+(1/this._pixelRatio)+') translateZ(0)'; + this.gl.viewport(0, 0, this._width* this._pixelRatio , this._height* this._pixelRatio ); + } + + clearColor(r, g, b, alpha) { + if (!this.gl) { + return; + } + this.gl.clearColor(r, g, b, alpha); + } + + clear(color, depth, stencil) { + if (!this.gl) { + return; + } + var bits = 0; + if ( color === void 0 || color ) bits |= this.gl.COLOR_BUFFER_BIT; + if ( depth === void 0 || depth ) bits |= this.gl.DEPTH_BUFFER_BIT; + if ( stencil === void 0 || stencil ) bits |= this.gl.STENCIL_BUFFER_BIT; + this.gl.clear( bits ); + } + + setPixelRatio(ratio) { + this._pixelRatio = ratio; + this.resize(this._width, this._height); + } + +} + + +export default Renderer; \ No newline at end of file diff --git a/src/globe/beam/Scene.js b/src/globe/beam/Scene.js new file mode 100755 index 0000000..4da2470 --- /dev/null +++ b/src/globe/beam/Scene.js @@ -0,0 +1,114 @@ +import {Light} from 'beam' +import {Container} from 'beam' +import {vec3, mat4} from 'beam' + + +var objects = [] + +function needsUpdateLoop() { + requestAnimationFrame(needsUpdateLoop); + for (let i=0; i 0 ) indices.push( a, b, d ); + if ( iy !== heightSegments - 1 || thetaEnd < Math.PI ) indices.push( b, c, d ); + } + } + + // build geometry + this.length = vertices.length/3; + + this.addAttribute( 'index', new Uint16Array( indices ), 1 ); + this.addAttribute( 'position', new Float32Array( vertices ), 3 ); + this.addAttribute( 'normal', new Float32Array( normals ), 3 ); + this.addAttribute( 'color', new Float32Array( colors ), 3 ); + this.addAttribute( 'uv', new Float32Array( uvs ), 2, 'Sphere' ); + + } + +} + +export default SphereGeometryBuffer; \ No newline at end of file diff --git a/src/globe/beam/Sprite.js b/src/globe/beam/Sprite.js new file mode 100755 index 0000000..d2c2471 --- /dev/null +++ b/src/globe/beam/Sprite.js @@ -0,0 +1,35 @@ +import Loader from './Loader'; +import Mesh from './Mesh'; +import Material from './Material'; +import Texture from './Texture'; +import PlaneGeometryBuffer from './PlaneGeometryBuffer'; + +class Sprite extends Mesh { + + constructor(gl, url) { + + super(); + + this.gl = gl; + + Loader.loadImage(url, (image)=>{ + + this.texture = Texture.fromImage( this.gl, image ); + + this.material = new Material(this.gl, { + blend: true + }); + this.material.map = this.texture; + + this.geometry = new PlaneGeometryBuffer(this.gl, { + width: Math.floor(image.width/10), + height: Math.floor(image.height/10), + }); + + }); + + } + +} + +export default Sprite; \ No newline at end of file diff --git a/src/globe/beam/Texture.js b/src/globe/beam/Texture.js new file mode 100755 index 0000000..bda6ab5 --- /dev/null +++ b/src/globe/beam/Texture.js @@ -0,0 +1,247 @@ +import uuid from './utils/uuid'; + +import getFilter from './utils/getFilter'; +import isPowerOf2 from './utils/isPowerOf2'; + +var TEXTURE_CACHE = {}; + +class Texture { + + constructor(gl, options) { + + + if (!gl) { + return; + } + + + this.options = Object.assign({}, { + format: gl.RGBA, + type: gl.UNSIGNED_BYTE, + width: 1, + height: 1, + linear: true, + mipmap: false, + miplinear: false, + wrapS: gl.CLAMP_TO_EDGE, + wrapT: gl.CLAMP_TO_EDGE, + anisotropy: 0, + flipY: true, + repeat: [1,1] + }, options); + + + this._uid = uuid();//debug purpose + this.gl = gl; + this.width = this.options.width; + this.height = this.options.height; + this.format = this.options.format; + this.type = this.options.type; + this.flipY = this.options.flipY; + + this.repeat = this.options.repeat; + + this._anisotropy = this.options.anisotropy; + + if (this.type == gl.FLOAT) { + var floatTextures = gl.getExtension('OES_texture_float'); + var floatTextureLinearFiltering = gl.getExtension('OES_texture_float_linear'); + if (!floatTextures) { + console.warn('trying to create a FrameBuffer of with gl.FLOAT type but there\s no floating point texture support. trying HALF_FLOAT'); + this.type = "HALF_FLOAT" + } + } + + if (this.type == "HALF_FLOAT") { + var halfFloatTexturesExt = gl.getExtension('OES_texture_half_float'); + var halfFloatTextureLinearFiltering = gl.getExtension('OES_texture_half_float_linear'); + if (!halfFloatTexturesExt) { + console.warn('trying to create a texture of with gl.HALF_FLOAT type but there\s no half floating point texture support; falling bck to UNSIGNED_BYTE type'); + this.type = gl.UNSIGNED_BYTE; + } + else { + this.type = halfFloatTexturesExt.HALF_FLOAT_OES; + this.isHalfFloat = true; + } + } + + this._texture = this.gl.createTexture(); + gl.bindTexture( gl.TEXTURE_2D, this._texture ); + + //1x1 pixel default texture + gl.texImage2D(gl.TEXTURE_2D, 0, this.options.format, this.width, this.height, 0, this.options.format, gl.UNSIGNED_BYTE, new Uint8Array([0, 0, 0, 255])); + + /** + * add getter and setter to update texture_wrap when this.wrap changes + */ + Object.defineProperty(this, 'wrapS', { + set: (value) => { + this.gl.texParameteri( this.gl.TEXTURE_2D, this.gl.TEXTURE_WRAP_S, value ); + } + }); + Object.defineProperty(this, 'wrapT', { + set: (value) => { + this.gl.texParameteri( this.gl.TEXTURE_2D, this.gl.TEXTURE_WRAP_T, value ); + } + }); + //nPOT texture can't repeat + this.wrapS = this.options.wrapS; + this.wrapT = this.options.wrapT; + + + //nPOT texture cannot mipmap + this.setFilter( this.options.linear, this.options.mipmap, this.options.mipmapLinear ); + + //unbind texture + gl.bindTexture( gl.TEXTURE_2D, null); + + + + Object.defineProperty(this, 'anisotropy', { + set: (value) => { + this._anisotropy = value + this.updateAnisotropyFilter() + }, + get: () => { + return this._anisotropy + } + }); + + } + + updateAnisotropyFilter() { + let gl = this.gl; + + if (!gl) { + return; + } + var ext = ( + gl.getExtension('EXT_texture_filter_anisotropic') || + gl.getExtension('MOZ_EXT_texture_filter_anisotropic') || + gl.getExtension('WEBKIT_EXT_texture_filter_anisotropic') + ); + if (ext) { + if (this._anisotropy > 0) { + gl.bindTexture( gl.TEXTURE_2D, this._texture ); + var max = gl.getParameter(ext.MAX_TEXTURE_MAX_ANISOTROPY_EXT); + gl.texParameterf(gl.TEXTURE_2D, ext.TEXTURE_MAX_ANISOTROPY_EXT, Math.min(this._anisotropy, max) ); + } + } + } + + bindImage(img) { + + if (!this.gl) { + return; + } + + this.width = img.width; + this.height = img.height; + var isPOT = isPowerOf2(img.width) && isPowerOf2(img.height); + + this.gl.bindTexture( this.gl.TEXTURE_2D, this._texture); + + this.gl.pixelStorei( this.gl.UNPACK_FLIP_Y_WEBGL, this.flipY); + + // console.log('BIND2D', img) + this.gl.texImage2D( this.gl.TEXTURE_2D, 0, this.format, this.format, this.type, img); + + if (isPOT) { + //nPOT texture cannot mipmap + this.setFilter( this.options.linear, this.options.mipmap, this.options.mipmapLinear ); + this.gl.generateMipmap(this.gl.TEXTURE_2D); + } + else { + this.setFilter(this.options.linear, false, false); + this.wrapS = this.gl.CLAMP_TO_EDGE; + this.wrapT = this.gl.CLAMP_TO_EDGE; + } + + this.gl.bindTexture( this.gl.TEXTURE_2D, null); + + } + + bind(unit) { + if (!this.gl) { + return; + } + //unit is sent by the Program and defined by the unfirom order in the shaders; + if (unit !== void 0) { + this.gl.activeTexture( this.gl.TEXTURE0 + (0|unit) ); + } + this.gl.bindTexture(this.gl.TEXTURE_2D, this._texture); + } + + delete() { + if (this.gl) { + this.gl.deleteTexture( this._texture ); + } + this._texture = null; + this.gl = null; + } + + /** + * Change the filtering parameters + * @param {boolean} [smooth=false] if true, use LINEAR filtering + * @param {boolean} [mipmap=false] if true, enable mipmaping + * @param {boolean} [miplinear=false] if true, use linear Mipmapping + */ + setFilter(smooth, mipmap, miplinear) { + + + if (!this.gl) { + return; + } + var gl = this.gl; + var filter = getFilter( !!smooth, !!mipmap, !!miplinear); + gl.bindTexture( gl.TEXTURE_2D, this._texture ); + gl.texParameteri( gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, getFilter( !!smooth, false, false ) ); + gl.texParameteri( gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, filter ); + this.updateAnisotropyFilter() + } + +} + + +Texture.fromUrl = function(gl, url, options) { + + var texture = new Texture(gl, options); + + // if (TEXTURE_CACHE[url] !== void 0) { + // this.fromImage( gl, TEXTURE_CACHE[url] ); + // return; + // } + + var img = new Image(); + + img.onload = ()=>{ + img.onload = null; + img.onerror = null; + TEXTURE_CACHE[url] = img; + texture.bindImage(img); + }; + + img.onerror = ()=>{ + img.onload = null; + img.onerror = null; + console.warn('Invalid url provided to Texture.fromUrl() : ' + url); + }; + + img.src = url; + + return texture; +}; + +Texture.fromImage = function(gl, img, options) { + if (!img.width || !img.height) { + console.warn('Cannot create texture with provided image\n Please make sure the image is loaded before calling Texture.fromImage() or use Texture.fromUrl()', img); + return; + } + var texture = new Texture(gl, options); + texture.bindImage(img); + return texture; +}; + + + +export default Texture; diff --git a/src/globe/beam/TriangleGeometryBuffer.js b/src/globe/beam/TriangleGeometryBuffer.js new file mode 100755 index 0000000..907a89a --- /dev/null +++ b/src/globe/beam/TriangleGeometryBuffer.js @@ -0,0 +1,32 @@ +import GeometryBuffer from './GeometryBuffer'; + +class TriangleGeometryBuffer extends GeometryBuffer { + + constructor(gl) { + + super(gl, 3.); + + this.addAttribute('position', new Float32Array([ + -1.0, -1.0, 0.0, + 0.0, 1.0, 0.0, + 1.0, -1.0, 0.0 + ]), 3); + + this.addAttribute('uv', new Float32Array([ + 0.0, 0.0, + 0.5, 1.0, + 1.0, 0.0, + ]), 2, 'triangle'); + + this.addAttribute('color', new Float32Array([ + 1.0, 1.0, 1.0, + 1.0, 1.0, 1.0, + 1.0, 1.0, 1.0 + ]), 3); + + + } + +} + +export default TriangleGeometryBuffer; \ No newline at end of file diff --git a/src/globe/beam/glMatrix/common.js b/src/globe/beam/glMatrix/common.js new file mode 100755 index 0000000..a67bac7 --- /dev/null +++ b/src/globe/beam/glMatrix/common.js @@ -0,0 +1,62 @@ +/* Copyright (c) 2015, Brandon Jones, Colin MacKenzie IV. + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. */ + +/** + * Common utilities + * @module glMatrix + */ + +// Configuration Constants +export const EPSILON = 0.000001; +export let ARRAY_TYPE = (typeof Float32Array !== 'undefined') ? Float32Array : Array; +export const RANDOM = Math.random; + +/** + * Sets the type of array used when creating new vectors and matrices + * + * @param {Type} type Array type, such as Float32Array or Array + */ +export function setMatrixArrayType(type) { + ARRAY_TYPE = type; +} + +const degree = Math.PI / 180; + +/** + * Convert Degree To Radian + * + * @param {Number} a Angle in Degrees + */ +export function toRadian(a) { + return a * degree; +} + +/** + * Tests whether or not the arguments have approximately the same value, within an absolute + * or relative tolerance of glMatrix.EPSILON (an absolute tolerance is used for values less + * than or equal to 1.0, and a relative tolerance is used for larger values) + * + * @param {Number} a The first number to test. + * @param {Number} b The second number to test. + * @returns {Boolean} True if the numbers are approximately equal, false otherwise. + */ +export function equals(a, b) { + return Math.abs(a - b) <= EPSILON*Math.max(1.0, Math.abs(a), Math.abs(b)); +} diff --git a/src/globe/beam/glMatrix/mat2.js b/src/globe/beam/glMatrix/mat2.js new file mode 100755 index 0000000..2c8d5b7 --- /dev/null +++ b/src/globe/beam/glMatrix/mat2.js @@ -0,0 +1,433 @@ +/* Copyright (c) 2015, Brandon Jones, Colin MacKenzie IV. + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. */ + +import * as glMatrix from "./common" + +/** + * 2x2 Matrix + * @module mat2 + */ + +/** + * Creates a new identity mat2 + * + * @returns {mat2} a new 2x2 matrix + */ +export function create() { + let out = new glMatrix.ARRAY_TYPE(4); + out[0] = 1; + out[1] = 0; + out[2] = 0; + out[3] = 1; + return out; +} + +/** + * Creates a new mat2 initialized with values from an existing matrix + * + * @param {mat2} a matrix to clone + * @returns {mat2} a new 2x2 matrix + */ +export function clone(a) { + let out = new glMatrix.ARRAY_TYPE(4); + out[0] = a[0]; + out[1] = a[1]; + out[2] = a[2]; + out[3] = a[3]; + return out; +} + +/** + * Copy the values from one mat2 to another + * + * @param {mat2} out the receiving matrix + * @param {mat2} a the source matrix + * @returns {mat2} out + */ +export function copy(out, a) { + out[0] = a[0]; + out[1] = a[1]; + out[2] = a[2]; + out[3] = a[3]; + return out; +} + +/** + * Set a mat2 to the identity matrix + * + * @param {mat2} out the receiving matrix + * @returns {mat2} out + */ +export function identity(out) { + out[0] = 1; + out[1] = 0; + out[2] = 0; + out[3] = 1; + return out; +} + +/** + * Create a new mat2 with the given values + * + * @param {Number} m00 Component in column 0, row 0 position (index 0) + * @param {Number} m01 Component in column 0, row 1 position (index 1) + * @param {Number} m10 Component in column 1, row 0 position (index 2) + * @param {Number} m11 Component in column 1, row 1 position (index 3) + * @returns {mat2} out A new 2x2 matrix + */ +export function fromValues(m00, m01, m10, m11) { + let out = new glMatrix.ARRAY_TYPE(4); + out[0] = m00; + out[1] = m01; + out[2] = m10; + out[3] = m11; + return out; +} + +/** + * Set the components of a mat2 to the given values + * + * @param {mat2} out the receiving matrix + * @param {Number} m00 Component in column 0, row 0 position (index 0) + * @param {Number} m01 Component in column 0, row 1 position (index 1) + * @param {Number} m10 Component in column 1, row 0 position (index 2) + * @param {Number} m11 Component in column 1, row 1 position (index 3) + * @returns {mat2} out + */ +export function set(out, m00, m01, m10, m11) { + out[0] = m00; + out[1] = m01; + out[2] = m10; + out[3] = m11; + return out; +} + +/** + * Transpose the values of a mat2 + * + * @param {mat2} out the receiving matrix + * @param {mat2} a the source matrix + * @returns {mat2} out + */ +export function transpose(out, a) { + // If we are transposing ourselves we can skip a few steps but have to cache + // some values + if (out === a) { + let a1 = a[1]; + out[1] = a[2]; + out[2] = a1; + } else { + out[0] = a[0]; + out[1] = a[2]; + out[2] = a[1]; + out[3] = a[3]; + } + + return out; +} + +/** + * Inverts a mat2 + * + * @param {mat2} out the receiving matrix + * @param {mat2} a the source matrix + * @returns {mat2} out + */ +export function invert(out, a) { + let a0 = a[0], a1 = a[1], a2 = a[2], a3 = a[3]; + + // Calculate the determinant + let det = a0 * a3 - a2 * a1; + + if (!det) { + return null; + } + det = 1.0 / det; + + out[0] = a3 * det; + out[1] = -a1 * det; + out[2] = -a2 * det; + out[3] = a0 * det; + + return out; +} + +/** + * Calculates the adjugate of a mat2 + * + * @param {mat2} out the receiving matrix + * @param {mat2} a the source matrix + * @returns {mat2} out + */ +export function adjoint(out, a) { + // Caching this value is nessecary if out == a + let a0 = a[0]; + out[0] = a[3]; + out[1] = -a[1]; + out[2] = -a[2]; + out[3] = a0; + + return out; +} + +/** + * Calculates the determinant of a mat2 + * + * @param {mat2} a the source matrix + * @returns {Number} determinant of a + */ +export function determinant(a) { + return a[0] * a[3] - a[2] * a[1]; +} + +/** + * Multiplies two mat2's + * + * @param {mat2} out the receiving matrix + * @param {mat2} a the first operand + * @param {mat2} b the second operand + * @returns {mat2} out + */ +export function multiply(out, a, b) { + let a0 = a[0], a1 = a[1], a2 = a[2], a3 = a[3]; + let b0 = b[0], b1 = b[1], b2 = b[2], b3 = b[3]; + out[0] = a0 * b0 + a2 * b1; + out[1] = a1 * b0 + a3 * b1; + out[2] = a0 * b2 + a2 * b3; + out[3] = a1 * b2 + a3 * b3; + return out; +} + +/** + * Rotates a mat2 by the given angle + * + * @param {mat2} out the receiving matrix + * @param {mat2} a the matrix to rotate + * @param {Number} rad the angle to rotate the matrix by + * @returns {mat2} out + */ +export function rotate(out, a, rad) { + let a0 = a[0], a1 = a[1], a2 = a[2], a3 = a[3]; + let s = Math.sin(rad); + let c = Math.cos(rad); + out[0] = a0 * c + a2 * s; + out[1] = a1 * c + a3 * s; + out[2] = a0 * -s + a2 * c; + out[3] = a1 * -s + a3 * c; + return out; +} + +/** + * Scales the mat2 by the dimensions in the given vec2 + * + * @param {mat2} out the receiving matrix + * @param {mat2} a the matrix to rotate + * @param {vec2} v the vec2 to scale the matrix by + * @returns {mat2} out + **/ +export function scale(out, a, v) { + let a0 = a[0], a1 = a[1], a2 = a[2], a3 = a[3]; + let v0 = v[0], v1 = v[1]; + out[0] = a0 * v0; + out[1] = a1 * v0; + out[2] = a2 * v1; + out[3] = a3 * v1; + return out; +} + +/** + * Creates a matrix from a given angle + * This is equivalent to (but much faster than): + * + * mat2.identity(dest); + * mat2.rotate(dest, dest, rad); + * + * @param {mat2} out mat2 receiving operation result + * @param {Number} rad the angle to rotate the matrix by + * @returns {mat2} out + */ +export function fromRotation(out, rad) { + let s = Math.sin(rad); + let c = Math.cos(rad); + out[0] = c; + out[1] = s; + out[2] = -s; + out[3] = c; + return out; +} + +/** + * Creates a matrix from a vector scaling + * This is equivalent to (but much faster than): + * + * mat2.identity(dest); + * mat2.scale(dest, dest, vec); + * + * @param {mat2} out mat2 receiving operation result + * @param {vec2} v Scaling vector + * @returns {mat2} out + */ +export function fromScaling(out, v) { + out[0] = v[0]; + out[1] = 0; + out[2] = 0; + out[3] = v[1]; + return out; +} + +/** + * Returns a string representation of a mat2 + * + * @param {mat2} a matrix to represent as a string + * @returns {String} string representation of the matrix + */ +export function str(a) { + return 'mat2(' + a[0] + ', ' + a[1] + ', ' + a[2] + ', ' + a[3] + ')'; +} + +/** + * Returns Frobenius norm of a mat2 + * + * @param {mat2} a the matrix to calculate Frobenius norm of + * @returns {Number} Frobenius norm + */ +export function frob(a) { + return(Math.sqrt(Math.pow(a[0], 2) + Math.pow(a[1], 2) + Math.pow(a[2], 2) + Math.pow(a[3], 2))) +} + +/** + * Returns L, D and U matrices (Lower triangular, Diagonal and Upper triangular) by factorizing the input matrix + * @param {mat2} L the lower triangular matrix + * @param {mat2} D the diagonal matrix + * @param {mat2} U the upper triangular matrix + * @param {mat2} a the input matrix to factorize + */ + +export function LDU(L, D, U, a) { + L[2] = a[2]/a[0]; + U[0] = a[0]; + U[1] = a[1]; + U[3] = a[3] - L[2] * U[1]; + return [L, D, U]; +} + +/** + * Adds two mat2's + * + * @param {mat2} out the receiving matrix + * @param {mat2} a the first operand + * @param {mat2} b the second operand + * @returns {mat2} out + */ +export function add(out, a, b) { + out[0] = a[0] + b[0]; + out[1] = a[1] + b[1]; + out[2] = a[2] + b[2]; + out[3] = a[3] + b[3]; + return out; +} + +/** + * Subtracts matrix b from matrix a + * + * @param {mat2} out the receiving matrix + * @param {mat2} a the first operand + * @param {mat2} b the second operand + * @returns {mat2} out + */ +export function subtract(out, a, b) { + out[0] = a[0] - b[0]; + out[1] = a[1] - b[1]; + out[2] = a[2] - b[2]; + out[3] = a[3] - b[3]; + return out; +} + +/** + * Returns whether or not the matrices have exactly the same elements in the same position (when compared with ===) + * + * @param {mat2} a The first matrix. + * @param {mat2} b The second matrix. + * @returns {Boolean} True if the matrices are equal, false otherwise. + */ +export function exactEquals(a, b) { + return a[0] === b[0] && a[1] === b[1] && a[2] === b[2] && a[3] === b[3]; +} + +/** + * Returns whether or not the matrices have approximately the same elements in the same position. + * + * @param {mat2} a The first matrix. + * @param {mat2} b The second matrix. + * @returns {Boolean} True if the matrices are equal, false otherwise. + */ +export function equals(a, b) { + let a0 = a[0], a1 = a[1], a2 = a[2], a3 = a[3]; + let b0 = b[0], b1 = b[1], b2 = b[2], b3 = b[3]; + return (Math.abs(a0 - b0) <= glMatrix.EPSILON*Math.max(1.0, Math.abs(a0), Math.abs(b0)) && + Math.abs(a1 - b1) <= glMatrix.EPSILON*Math.max(1.0, Math.abs(a1), Math.abs(b1)) && + Math.abs(a2 - b2) <= glMatrix.EPSILON*Math.max(1.0, Math.abs(a2), Math.abs(b2)) && + Math.abs(a3 - b3) <= glMatrix.EPSILON*Math.max(1.0, Math.abs(a3), Math.abs(b3))); +} + +/** + * Multiply each element of the matrix by a scalar. + * + * @param {mat2} out the receiving matrix + * @param {mat2} a the matrix to scale + * @param {Number} b amount to scale the matrix's elements by + * @returns {mat2} out + */ +export function multiplyScalar(out, a, b) { + out[0] = a[0] * b; + out[1] = a[1] * b; + out[2] = a[2] * b; + out[3] = a[3] * b; + return out; +} + +/** + * Adds two mat2's after multiplying each element of the second operand by a scalar value. + * + * @param {mat2} out the receiving vector + * @param {mat2} a the first operand + * @param {mat2} b the second operand + * @param {Number} scale the amount to scale b's elements by before adding + * @returns {mat2} out + */ +export function multiplyScalarAndAdd(out, a, b, scale) { + out[0] = a[0] + (b[0] * scale); + out[1] = a[1] + (b[1] * scale); + out[2] = a[2] + (b[2] * scale); + out[3] = a[3] + (b[3] * scale); + return out; +} + +/** + * Alias for {@link mat2.multiply} + * @function + */ +export const mul = multiply; + +/** + * Alias for {@link mat2.subtract} + * @function + */ +export const sub = subtract; diff --git a/src/globe/beam/glMatrix/mat2d.js b/src/globe/beam/glMatrix/mat2d.js new file mode 100755 index 0000000..577783b --- /dev/null +++ b/src/globe/beam/glMatrix/mat2d.js @@ -0,0 +1,466 @@ +/* Copyright (c) 2015, Brandon Jones, Colin MacKenzie IV. + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. */ + +import * as glMatrix from "./common"; + +/** + * 2x3 Matrix + * @module mat2d + * + * @description + * A mat2d contains six elements defined as: + *
+ * [a, c, tx,
+ *  b, d, ty]
+ * 
+ * This is a short form for the 3x3 matrix: + *
+ * [a, c, tx,
+ *  b, d, ty,
+ *  0, 0, 1]
+ * 
+ * The last row is ignored so the array is shorter and operations are faster. + */ + +/** + * Creates a new identity mat2d + * + * @returns {mat2d} a new 2x3 matrix + */ +export function create() { + let out = new glMatrix.ARRAY_TYPE(6); + out[0] = 1; + out[1] = 0; + out[2] = 0; + out[3] = 1; + out[4] = 0; + out[5] = 0; + return out; +} + +/** + * Creates a new mat2d initialized with values from an existing matrix + * + * @param {mat2d} a matrix to clone + * @returns {mat2d} a new 2x3 matrix + */ +export function clone(a) { + let out = new glMatrix.ARRAY_TYPE(6); + out[0] = a[0]; + out[1] = a[1]; + out[2] = a[2]; + out[3] = a[3]; + out[4] = a[4]; + out[5] = a[5]; + return out; +} + +/** + * Copy the values from one mat2d to another + * + * @param {mat2d} out the receiving matrix + * @param {mat2d} a the source matrix + * @returns {mat2d} out + */ +export function copy(out, a) { + out[0] = a[0]; + out[1] = a[1]; + out[2] = a[2]; + out[3] = a[3]; + out[4] = a[4]; + out[5] = a[5]; + return out; +} + +/** + * Set a mat2d to the identity matrix + * + * @param {mat2d} out the receiving matrix + * @returns {mat2d} out + */ +export function identity(out) { + out[0] = 1; + out[1] = 0; + out[2] = 0; + out[3] = 1; + out[4] = 0; + out[5] = 0; + return out; +} + +/** + * Create a new mat2d with the given values + * + * @param {Number} a Component A (index 0) + * @param {Number} b Component B (index 1) + * @param {Number} c Component C (index 2) + * @param {Number} d Component D (index 3) + * @param {Number} tx Component TX (index 4) + * @param {Number} ty Component TY (index 5) + * @returns {mat2d} A new mat2d + */ +export function fromValues(a, b, c, d, tx, ty) { + let out = new glMatrix.ARRAY_TYPE(6); + out[0] = a; + out[1] = b; + out[2] = c; + out[3] = d; + out[4] = tx; + out[5] = ty; + return out; +} + +/** + * Set the components of a mat2d to the given values + * + * @param {mat2d} out the receiving matrix + * @param {Number} a Component A (index 0) + * @param {Number} b Component B (index 1) + * @param {Number} c Component C (index 2) + * @param {Number} d Component D (index 3) + * @param {Number} tx Component TX (index 4) + * @param {Number} ty Component TY (index 5) + * @returns {mat2d} out + */ +export function set(out, a, b, c, d, tx, ty) { + out[0] = a; + out[1] = b; + out[2] = c; + out[3] = d; + out[4] = tx; + out[5] = ty; + return out; +} + +/** + * Inverts a mat2d + * + * @param {mat2d} out the receiving matrix + * @param {mat2d} a the source matrix + * @returns {mat2d} out + */ +export function invert(out, a) { + let aa = a[0], ab = a[1], ac = a[2], ad = a[3]; + let atx = a[4], aty = a[5]; + + let det = aa * ad - ab * ac; + if(!det){ + return null; + } + det = 1.0 / det; + + out[0] = ad * det; + out[1] = -ab * det; + out[2] = -ac * det; + out[3] = aa * det; + out[4] = (ac * aty - ad * atx) * det; + out[5] = (ab * atx - aa * aty) * det; + return out; +} + +/** + * Calculates the determinant of a mat2d + * + * @param {mat2d} a the source matrix + * @returns {Number} determinant of a + */ +export function determinant(a) { + return a[0] * a[3] - a[1] * a[2]; +} + +/** + * Multiplies two mat2d's + * + * @param {mat2d} out the receiving matrix + * @param {mat2d} a the first operand + * @param {mat2d} b the second operand + * @returns {mat2d} out + */ +export function multiply(out, a, b) { + let a0 = a[0], a1 = a[1], a2 = a[2], a3 = a[3], a4 = a[4], a5 = a[5]; + let b0 = b[0], b1 = b[1], b2 = b[2], b3 = b[3], b4 = b[4], b5 = b[5]; + out[0] = a0 * b0 + a2 * b1; + out[1] = a1 * b0 + a3 * b1; + out[2] = a0 * b2 + a2 * b3; + out[3] = a1 * b2 + a3 * b3; + out[4] = a0 * b4 + a2 * b5 + a4; + out[5] = a1 * b4 + a3 * b5 + a5; + return out; +} + +/** + * Rotates a mat2d by the given angle + * + * @param {mat2d} out the receiving matrix + * @param {mat2d} a the matrix to rotate + * @param {Number} rad the angle to rotate the matrix by + * @returns {mat2d} out + */ +export function rotate(out, a, rad) { + let a0 = a[0], a1 = a[1], a2 = a[2], a3 = a[3], a4 = a[4], a5 = a[5]; + let s = Math.sin(rad); + let c = Math.cos(rad); + out[0] = a0 * c + a2 * s; + out[1] = a1 * c + a3 * s; + out[2] = a0 * -s + a2 * c; + out[3] = a1 * -s + a3 * c; + out[4] = a4; + out[5] = a5; + return out; +} + +/** + * Scales the mat2d by the dimensions in the given vec2 + * + * @param {mat2d} out the receiving matrix + * @param {mat2d} a the matrix to translate + * @param {vec2} v the vec2 to scale the matrix by + * @returns {mat2d} out + **/ +export function scale(out, a, v) { + let a0 = a[0], a1 = a[1], a2 = a[2], a3 = a[3], a4 = a[4], a5 = a[5]; + let v0 = v[0], v1 = v[1]; + out[0] = a0 * v0; + out[1] = a1 * v0; + out[2] = a2 * v1; + out[3] = a3 * v1; + out[4] = a4; + out[5] = a5; + return out; +} + +/** + * Translates the mat2d by the dimensions in the given vec2 + * + * @param {mat2d} out the receiving matrix + * @param {mat2d} a the matrix to translate + * @param {vec2} v the vec2 to translate the matrix by + * @returns {mat2d} out + **/ +export function translate(out, a, v) { + let a0 = a[0], a1 = a[1], a2 = a[2], a3 = a[3], a4 = a[4], a5 = a[5]; + let v0 = v[0], v1 = v[1]; + out[0] = a0; + out[1] = a1; + out[2] = a2; + out[3] = a3; + out[4] = a0 * v0 + a2 * v1 + a4; + out[5] = a1 * v0 + a3 * v1 + a5; + return out; +} + +/** + * Creates a matrix from a given angle + * This is equivalent to (but much faster than): + * + * mat2d.identity(dest); + * mat2d.rotate(dest, dest, rad); + * + * @param {mat2d} out mat2d receiving operation result + * @param {Number} rad the angle to rotate the matrix by + * @returns {mat2d} out + */ +export function fromRotation(out, rad) { + let s = Math.sin(rad), c = Math.cos(rad); + out[0] = c; + out[1] = s; + out[2] = -s; + out[3] = c; + out[4] = 0; + out[5] = 0; + return out; +} + +/** + * Creates a matrix from a vector scaling + * This is equivalent to (but much faster than): + * + * mat2d.identity(dest); + * mat2d.scale(dest, dest, vec); + * + * @param {mat2d} out mat2d receiving operation result + * @param {vec2} v Scaling vector + * @returns {mat2d} out + */ +export function fromScaling(out, v) { + out[0] = v[0]; + out[1] = 0; + out[2] = 0; + out[3] = v[1]; + out[4] = 0; + out[5] = 0; + return out; +} + +/** + * Creates a matrix from a vector translation + * This is equivalent to (but much faster than): + * + * mat2d.identity(dest); + * mat2d.translate(dest, dest, vec); + * + * @param {mat2d} out mat2d receiving operation result + * @param {vec2} v Translation vector + * @returns {mat2d} out + */ +export function fromTranslation(out, v) { + out[0] = 1; + out[1] = 0; + out[2] = 0; + out[3] = 1; + out[4] = v[0]; + out[5] = v[1]; + return out; +} + +/** + * Returns a string representation of a mat2d + * + * @param {mat2d} a matrix to represent as a string + * @returns {String} string representation of the matrix + */ +export function str(a) { + return 'mat2d(' + a[0] + ', ' + a[1] + ', ' + a[2] + ', ' + + a[3] + ', ' + a[4] + ', ' + a[5] + ')'; +} + +/** + * Returns Frobenius norm of a mat2d + * + * @param {mat2d} a the matrix to calculate Frobenius norm of + * @returns {Number} Frobenius norm + */ +export function frob(a) { + return(Math.sqrt(Math.pow(a[0], 2) + Math.pow(a[1], 2) + Math.pow(a[2], 2) + Math.pow(a[3], 2) + Math.pow(a[4], 2) + Math.pow(a[5], 2) + 1)) +} + +/** + * Adds two mat2d's + * + * @param {mat2d} out the receiving matrix + * @param {mat2d} a the first operand + * @param {mat2d} b the second operand + * @returns {mat2d} out + */ +export function add(out, a, b) { + out[0] = a[0] + b[0]; + out[1] = a[1] + b[1]; + out[2] = a[2] + b[2]; + out[3] = a[3] + b[3]; + out[4] = a[4] + b[4]; + out[5] = a[5] + b[5]; + return out; +} + +/** + * Subtracts matrix b from matrix a + * + * @param {mat2d} out the receiving matrix + * @param {mat2d} a the first operand + * @param {mat2d} b the second operand + * @returns {mat2d} out + */ +export function subtract(out, a, b) { + out[0] = a[0] - b[0]; + out[1] = a[1] - b[1]; + out[2] = a[2] - b[2]; + out[3] = a[3] - b[3]; + out[4] = a[4] - b[4]; + out[5] = a[5] - b[5]; + return out; +} + +/** + * Multiply each element of the matrix by a scalar. + * + * @param {mat2d} out the receiving matrix + * @param {mat2d} a the matrix to scale + * @param {Number} b amount to scale the matrix's elements by + * @returns {mat2d} out + */ +export function multiplyScalar(out, a, b) { + out[0] = a[0] * b; + out[1] = a[1] * b; + out[2] = a[2] * b; + out[3] = a[3] * b; + out[4] = a[4] * b; + out[5] = a[5] * b; + return out; +} + +/** + * Adds two mat2d's after multiplying each element of the second operand by a scalar value. + * + * @param {mat2d} out the receiving vector + * @param {mat2d} a the first operand + * @param {mat2d} b the second operand + * @param {Number} scale the amount to scale b's elements by before adding + * @returns {mat2d} out + */ +export function multiplyScalarAndAdd(out, a, b, scale) { + out[0] = a[0] + (b[0] * scale); + out[1] = a[1] + (b[1] * scale); + out[2] = a[2] + (b[2] * scale); + out[3] = a[3] + (b[3] * scale); + out[4] = a[4] + (b[4] * scale); + out[5] = a[5] + (b[5] * scale); + return out; +} + +/** + * Returns whether or not the matrices have exactly the same elements in the same position (when compared with ===) + * + * @param {mat2d} a The first matrix. + * @param {mat2d} b The second matrix. + * @returns {Boolean} True if the matrices are equal, false otherwise. + */ +export function exactEquals(a, b) { + return a[0] === b[0] && a[1] === b[1] && a[2] === b[2] && a[3] === b[3] && a[4] === b[4] && a[5] === b[5]; +} + +/** + * Returns whether or not the matrices have approximately the same elements in the same position. + * + * @param {mat2d} a The first matrix. + * @param {mat2d} b The second matrix. + * @returns {Boolean} True if the matrices are equal, false otherwise. + */ +export function equals(a, b) { + let a0 = a[0], a1 = a[1], a2 = a[2], a3 = a[3], a4 = a[4], a5 = a[5]; + let b0 = b[0], b1 = b[1], b2 = b[2], b3 = b[3], b4 = b[4], b5 = b[5]; + return (Math.abs(a0 - b0) <= glMatrix.EPSILON*Math.max(1.0, Math.abs(a0), Math.abs(b0)) && + Math.abs(a1 - b1) <= glMatrix.EPSILON*Math.max(1.0, Math.abs(a1), Math.abs(b1)) && + Math.abs(a2 - b2) <= glMatrix.EPSILON*Math.max(1.0, Math.abs(a2), Math.abs(b2)) && + Math.abs(a3 - b3) <= glMatrix.EPSILON*Math.max(1.0, Math.abs(a3), Math.abs(b3)) && + Math.abs(a4 - b4) <= glMatrix.EPSILON*Math.max(1.0, Math.abs(a4), Math.abs(b4)) && + Math.abs(a5 - b5) <= glMatrix.EPSILON*Math.max(1.0, Math.abs(a5), Math.abs(b5))); +} + +/** + * Alias for {@link mat2d.multiply} + * @function + */ +export const mul = multiply; + +/** + * Alias for {@link mat2d.subtract} + * @function + */ +export const sub = subtract; diff --git a/src/globe/beam/glMatrix/mat3.js b/src/globe/beam/glMatrix/mat3.js new file mode 100755 index 0000000..ecccb02 --- /dev/null +++ b/src/globe/beam/glMatrix/mat3.js @@ -0,0 +1,765 @@ +/* Copyright (c) 2015, Brandon Jones, Colin MacKenzie IV. + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. */ + +import * as glMatrix from "./common"; + +/** + * 3x3 Matrix + * @module mat3 + */ + +/** + * Creates a new identity mat3 + * + * @returns {mat3} a new 3x3 matrix + */ +export function create() { + let out = new glMatrix.ARRAY_TYPE(9); + out[0] = 1; + out[1] = 0; + out[2] = 0; + out[3] = 0; + out[4] = 1; + out[5] = 0; + out[6] = 0; + out[7] = 0; + out[8] = 1; + return out; +} + +/** + * Copies the upper-left 3x3 values into the given mat3. + * + * @param {mat3} out the receiving 3x3 matrix + * @param {mat4} a the source 4x4 matrix + * @returns {mat3} out + */ +export function fromMat4(out, a) { + out[0] = a[0]; + out[1] = a[1]; + out[2] = a[2]; + out[3] = a[4]; + out[4] = a[5]; + out[5] = a[6]; + out[6] = a[8]; + out[7] = a[9]; + out[8] = a[10]; + return out; +} + +/** + * Creates a new mat3 initialized with values from an existing matrix + * + * @param {mat3} a matrix to clone + * @returns {mat3} a new 3x3 matrix + */ +export function clone(a) { + let out = new glMatrix.ARRAY_TYPE(9); + out[0] = a[0]; + out[1] = a[1]; + out[2] = a[2]; + out[3] = a[3]; + out[4] = a[4]; + out[5] = a[5]; + out[6] = a[6]; + out[7] = a[7]; + out[8] = a[8]; + return out; +} + +/** + * Copy the values from one mat3 to another + * + * @param {mat3} out the receiving matrix + * @param {mat3} a the source matrix + * @returns {mat3} out + */ +export function copy(out, a) { + out[0] = a[0]; + out[1] = a[1]; + out[2] = a[2]; + out[3] = a[3]; + out[4] = a[4]; + out[5] = a[5]; + out[6] = a[6]; + out[7] = a[7]; + out[8] = a[8]; + return out; +} + +/** + * Create a new mat3 with the given values + * + * @param {Number} m00 Component in column 0, row 0 position (index 0) + * @param {Number} m01 Component in column 0, row 1 position (index 1) + * @param {Number} m02 Component in column 0, row 2 position (index 2) + * @param {Number} m10 Component in column 1, row 0 position (index 3) + * @param {Number} m11 Component in column 1, row 1 position (index 4) + * @param {Number} m12 Component in column 1, row 2 position (index 5) + * @param {Number} m20 Component in column 2, row 0 position (index 6) + * @param {Number} m21 Component in column 2, row 1 position (index 7) + * @param {Number} m22 Component in column 2, row 2 position (index 8) + * @returns {mat3} A new mat3 + */ +export function fromValues(m00, m01, m02, m10, m11, m12, m20, m21, m22) { + let out = new glMatrix.ARRAY_TYPE(9); + out[0] = m00; + out[1] = m01; + out[2] = m02; + out[3] = m10; + out[4] = m11; + out[5] = m12; + out[6] = m20; + out[7] = m21; + out[8] = m22; + return out; +} + +/** + * Set the components of a mat3 to the given values + * + * @param {mat3} out the receiving matrix + * @param {Number} m00 Component in column 0, row 0 position (index 0) + * @param {Number} m01 Component in column 0, row 1 position (index 1) + * @param {Number} m02 Component in column 0, row 2 position (index 2) + * @param {Number} m10 Component in column 1, row 0 position (index 3) + * @param {Number} m11 Component in column 1, row 1 position (index 4) + * @param {Number} m12 Component in column 1, row 2 position (index 5) + * @param {Number} m20 Component in column 2, row 0 position (index 6) + * @param {Number} m21 Component in column 2, row 1 position (index 7) + * @param {Number} m22 Component in column 2, row 2 position (index 8) + * @returns {mat3} out + */ +export function set(out, m00, m01, m02, m10, m11, m12, m20, m21, m22) { + out[0] = m00; + out[1] = m01; + out[2] = m02; + out[3] = m10; + out[4] = m11; + out[5] = m12; + out[6] = m20; + out[7] = m21; + out[8] = m22; + return out; +} + +/** + * Set a mat3 to the identity matrix + * + * @param {mat3} out the receiving matrix + * @returns {mat3} out + */ +export function identity(out) { + out[0] = 1; + out[1] = 0; + out[2] = 0; + out[3] = 0; + out[4] = 1; + out[5] = 0; + out[6] = 0; + out[7] = 0; + out[8] = 1; + return out; +} + +/** + * Transpose the values of a mat3 + * + * @param {mat3} out the receiving matrix + * @param {mat3} a the source matrix + * @returns {mat3} out + */ +export function transpose(out, a) { + // If we are transposing ourselves we can skip a few steps but have to cache some values + if (out === a) { + let a01 = a[1], a02 = a[2], a12 = a[5]; + out[1] = a[3]; + out[2] = a[6]; + out[3] = a01; + out[5] = a[7]; + out[6] = a02; + out[7] = a12; + } else { + out[0] = a[0]; + out[1] = a[3]; + out[2] = a[6]; + out[3] = a[1]; + out[4] = a[4]; + out[5] = a[7]; + out[6] = a[2]; + out[7] = a[5]; + out[8] = a[8]; + } + + return out; +} + +/** + * Inverts a mat3 + * + * @param {mat3} out the receiving matrix + * @param {mat3} a the source matrix + * @returns {mat3} out + */ +export function invert(out, a) { + let a00 = a[0], a01 = a[1], a02 = a[2]; + let a10 = a[3], a11 = a[4], a12 = a[5]; + let a20 = a[6], a21 = a[7], a22 = a[8]; + + let b01 = a22 * a11 - a12 * a21; + let b11 = -a22 * a10 + a12 * a20; + let b21 = a21 * a10 - a11 * a20; + + // Calculate the determinant + let det = a00 * b01 + a01 * b11 + a02 * b21; + + if (!det) { + return null; + } + det = 1.0 / det; + + out[0] = b01 * det; + out[1] = (-a22 * a01 + a02 * a21) * det; + out[2] = (a12 * a01 - a02 * a11) * det; + out[3] = b11 * det; + out[4] = (a22 * a00 - a02 * a20) * det; + out[5] = (-a12 * a00 + a02 * a10) * det; + out[6] = b21 * det; + out[7] = (-a21 * a00 + a01 * a20) * det; + out[8] = (a11 * a00 - a01 * a10) * det; + return out; +} + +/** + * Calculates the adjugate of a mat3 + * + * @param {mat3} out the receiving matrix + * @param {mat3} a the source matrix + * @returns {mat3} out + */ +export function adjoint(out, a) { + let a00 = a[0], a01 = a[1], a02 = a[2]; + let a10 = a[3], a11 = a[4], a12 = a[5]; + let a20 = a[6], a21 = a[7], a22 = a[8]; + + out[0] = (a11 * a22 - a12 * a21); + out[1] = (a02 * a21 - a01 * a22); + out[2] = (a01 * a12 - a02 * a11); + out[3] = (a12 * a20 - a10 * a22); + out[4] = (a00 * a22 - a02 * a20); + out[5] = (a02 * a10 - a00 * a12); + out[6] = (a10 * a21 - a11 * a20); + out[7] = (a01 * a20 - a00 * a21); + out[8] = (a00 * a11 - a01 * a10); + return out; +} + +/** + * Calculates the determinant of a mat3 + * + * @param {mat3} a the source matrix + * @returns {Number} determinant of a + */ +export function determinant(a) { + let a00 = a[0], a01 = a[1], a02 = a[2]; + let a10 = a[3], a11 = a[4], a12 = a[5]; + let a20 = a[6], a21 = a[7], a22 = a[8]; + + return a00 * (a22 * a11 - a12 * a21) + a01 * (-a22 * a10 + a12 * a20) + a02 * (a21 * a10 - a11 * a20); +} + +/** + * Multiplies two mat3's + * + * @param {mat3} out the receiving matrix + * @param {mat3} a the first operand + * @param {mat3} b the second operand + * @returns {mat3} out + */ +export function multiply(out, a, b) { + let a00 = a[0], a01 = a[1], a02 = a[2]; + let a10 = a[3], a11 = a[4], a12 = a[5]; + let a20 = a[6], a21 = a[7], a22 = a[8]; + + let b00 = b[0], b01 = b[1], b02 = b[2]; + let b10 = b[3], b11 = b[4], b12 = b[5]; + let b20 = b[6], b21 = b[7], b22 = b[8]; + + out[0] = b00 * a00 + b01 * a10 + b02 * a20; + out[1] = b00 * a01 + b01 * a11 + b02 * a21; + out[2] = b00 * a02 + b01 * a12 + b02 * a22; + + out[3] = b10 * a00 + b11 * a10 + b12 * a20; + out[4] = b10 * a01 + b11 * a11 + b12 * a21; + out[5] = b10 * a02 + b11 * a12 + b12 * a22; + + out[6] = b20 * a00 + b21 * a10 + b22 * a20; + out[7] = b20 * a01 + b21 * a11 + b22 * a21; + out[8] = b20 * a02 + b21 * a12 + b22 * a22; + return out; +} + +/** + * Translate a mat3 by the given vector + * + * @param {mat3} out the receiving matrix + * @param {mat3} a the matrix to translate + * @param {vec2} v vector to translate by + * @returns {mat3} out + */ +export function translate(out, a, v) { + let a00 = a[0], a01 = a[1], a02 = a[2], + a10 = a[3], a11 = a[4], a12 = a[5], + a20 = a[6], a21 = a[7], a22 = a[8], + x = v[0], y = v[1]; + + out[0] = a00; + out[1] = a01; + out[2] = a02; + + out[3] = a10; + out[4] = a11; + out[5] = a12; + + out[6] = x * a00 + y * a10 + a20; + out[7] = x * a01 + y * a11 + a21; + out[8] = x * a02 + y * a12 + a22; + return out; +} + +/** + * Rotates a mat3 by the given angle + * + * @param {mat3} out the receiving matrix + * @param {mat3} a the matrix to rotate + * @param {Number} rad the angle to rotate the matrix by + * @returns {mat3} out + */ +export function rotate(out, a, rad) { + let a00 = a[0], a01 = a[1], a02 = a[2], + a10 = a[3], a11 = a[4], a12 = a[5], + a20 = a[6], a21 = a[7], a22 = a[8], + + s = Math.sin(rad), + c = Math.cos(rad); + + out[0] = c * a00 + s * a10; + out[1] = c * a01 + s * a11; + out[2] = c * a02 + s * a12; + + out[3] = c * a10 - s * a00; + out[4] = c * a11 - s * a01; + out[5] = c * a12 - s * a02; + + out[6] = a20; + out[7] = a21; + out[8] = a22; + return out; +}; + +/** + * Scales the mat3 by the dimensions in the given vec2 + * + * @param {mat3} out the receiving matrix + * @param {mat3} a the matrix to rotate + * @param {vec2} v the vec2 to scale the matrix by + * @returns {mat3} out + **/ +export function scale(out, a, v) { + let x = v[0], y = v[1]; + + out[0] = x * a[0]; + out[1] = x * a[1]; + out[2] = x * a[2]; + + out[3] = y * a[3]; + out[4] = y * a[4]; + out[5] = y * a[5]; + + out[6] = a[6]; + out[7] = a[7]; + out[8] = a[8]; + return out; +} + +/** + * Creates a matrix from a vector translation + * This is equivalent to (but much faster than): + * + * mat3.identity(dest); + * mat3.translate(dest, dest, vec); + * + * @param {mat3} out mat3 receiving operation result + * @param {vec2} v Translation vector + * @returns {mat3} out + */ +export function fromTranslation(out, v) { + out[0] = 1; + out[1] = 0; + out[2] = 0; + out[3] = 0; + out[4] = 1; + out[5] = 0; + out[6] = v[0]; + out[7] = v[1]; + out[8] = 1; + return out; +} + +/** + * Creates a matrix from a given angle + * This is equivalent to (but much faster than): + * + * mat3.identity(dest); + * mat3.rotate(dest, dest, rad); + * + * @param {mat3} out mat3 receiving operation result + * @param {Number} rad the angle to rotate the matrix by + * @returns {mat3} out + */ +export function fromRotation(out, rad) { + let s = Math.sin(rad), c = Math.cos(rad); + + out[0] = c; + out[1] = s; + out[2] = 0; + + out[3] = -s; + out[4] = c; + out[5] = 0; + + out[6] = 0; + out[7] = 0; + out[8] = 1; + return out; +} + +/** + * Creates a matrix from a vector scaling + * This is equivalent to (but much faster than): + * + * mat3.identity(dest); + * mat3.scale(dest, dest, vec); + * + * @param {mat3} out mat3 receiving operation result + * @param {vec2} v Scaling vector + * @returns {mat3} out + */ +export function fromScaling(out, v) { + out[0] = v[0]; + out[1] = 0; + out[2] = 0; + + out[3] = 0; + out[4] = v[1]; + out[5] = 0; + + out[6] = 0; + out[7] = 0; + out[8] = 1; + return out; +} + +/** + * Copies the values from a mat2d into a mat3 + * + * @param {mat3} out the receiving matrix + * @param {mat2d} a the matrix to copy + * @returns {mat3} out + **/ +export function fromMat2d(out, a) { + out[0] = a[0]; + out[1] = a[1]; + out[2] = 0; + + out[3] = a[2]; + out[4] = a[3]; + out[5] = 0; + + out[6] = a[4]; + out[7] = a[5]; + out[8] = 1; + return out; +} + +/** +* Calculates a 3x3 matrix from the given quaternion +* +* @param {mat3} out mat3 receiving operation result +* @param {quat} q Quaternion to create matrix from +* +* @returns {mat3} out +*/ +export function fromQuat(out, q) { + let x = q[0], y = q[1], z = q[2], w = q[3]; + let x2 = x + x; + let y2 = y + y; + let z2 = z + z; + + let xx = x * x2; + let yx = y * x2; + let yy = y * y2; + let zx = z * x2; + let zy = z * y2; + let zz = z * z2; + let wx = w * x2; + let wy = w * y2; + let wz = w * z2; + + out[0] = 1 - yy - zz; + out[3] = yx - wz; + out[6] = zx + wy; + + out[1] = yx + wz; + out[4] = 1 - xx - zz; + out[7] = zy - wx; + + out[2] = zx - wy; + out[5] = zy + wx; + out[8] = 1 - xx - yy; + + return out; +} + +/** +* Calculates a 3x3 normal matrix (transpose inverse) from the 4x4 matrix +* +* @param {mat3} out mat3 receiving operation result +* @param {mat4} a Mat4 to derive the normal matrix from +* +* @returns {mat3} out +*/ +export function normalFromMat4(out, a) { + let a00 = a[0], a01 = a[1], a02 = a[2], a03 = a[3]; + let a10 = a[4], a11 = a[5], a12 = a[6], a13 = a[7]; + let a20 = a[8], a21 = a[9], a22 = a[10], a23 = a[11]; + let a30 = a[12], a31 = a[13], a32 = a[14], a33 = a[15]; + + let b00 = a00 * a11 - a01 * a10; + let b01 = a00 * a12 - a02 * a10; + let b02 = a00 * a13 - a03 * a10; + let b03 = a01 * a12 - a02 * a11; + let b04 = a01 * a13 - a03 * a11; + let b05 = a02 * a13 - a03 * a12; + let b06 = a20 * a31 - a21 * a30; + let b07 = a20 * a32 - a22 * a30; + let b08 = a20 * a33 - a23 * a30; + let b09 = a21 * a32 - a22 * a31; + let b10 = a21 * a33 - a23 * a31; + let b11 = a22 * a33 - a23 * a32; + + // Calculate the determinant + let det = b00 * b11 - b01 * b10 + b02 * b09 + b03 * b08 - b04 * b07 + b05 * b06; + + if (!det) { + return null; + } + det = 1.0 / det; + + out[0] = (a11 * b11 - a12 * b10 + a13 * b09) * det; + out[1] = (a12 * b08 - a10 * b11 - a13 * b07) * det; + out[2] = (a10 * b10 - a11 * b08 + a13 * b06) * det; + + out[3] = (a02 * b10 - a01 * b11 - a03 * b09) * det; + out[4] = (a00 * b11 - a02 * b08 + a03 * b07) * det; + out[5] = (a01 * b08 - a00 * b10 - a03 * b06) * det; + + out[6] = (a31 * b05 - a32 * b04 + a33 * b03) * det; + out[7] = (a32 * b02 - a30 * b05 - a33 * b01) * det; + out[8] = (a30 * b04 - a31 * b02 + a33 * b00) * det; + + return out; +} + +/** + * Generates a 2D projection matrix with the given bounds + * + * @param {mat3} out mat3 frustum matrix will be written into + * @param {number} width Width of your gl context + * @param {number} height Height of gl context + * @returns {mat3} out + */ +export function projection(out, width, height) { + out[0] = 2 / width; + out[1] = 0; + out[2] = 0; + out[3] = 0; + out[4] = -2 / height; + out[5] = 0; + out[6] = -1; + out[7] = 1; + out[8] = 1; + return out; +} + +/** + * Returns a string representation of a mat3 + * + * @param {mat3} a matrix to represent as a string + * @returns {String} string representation of the matrix + */ +export function str(a) { + return 'mat3(' + a[0] + ', ' + a[1] + ', ' + a[2] + ', ' + + a[3] + ', ' + a[4] + ', ' + a[5] + ', ' + + a[6] + ', ' + a[7] + ', ' + a[8] + ')'; +} + +/** + * Returns Frobenius norm of a mat3 + * + * @param {mat3} a the matrix to calculate Frobenius norm of + * @returns {Number} Frobenius norm + */ +export function frob(a) { + return(Math.sqrt(Math.pow(a[0], 2) + Math.pow(a[1], 2) + Math.pow(a[2], 2) + Math.pow(a[3], 2) + Math.pow(a[4], 2) + Math.pow(a[5], 2) + Math.pow(a[6], 2) + Math.pow(a[7], 2) + Math.pow(a[8], 2))) +} + +/** + * Adds two mat3's + * + * @param {mat3} out the receiving matrix + * @param {mat3} a the first operand + * @param {mat3} b the second operand + * @returns {mat3} out + */ +export function add(out, a, b) { + out[0] = a[0] + b[0]; + out[1] = a[1] + b[1]; + out[2] = a[2] + b[2]; + out[3] = a[3] + b[3]; + out[4] = a[4] + b[4]; + out[5] = a[5] + b[5]; + out[6] = a[6] + b[6]; + out[7] = a[7] + b[7]; + out[8] = a[8] + b[8]; + return out; +} + +/** + * Subtracts matrix b from matrix a + * + * @param {mat3} out the receiving matrix + * @param {mat3} a the first operand + * @param {mat3} b the second operand + * @returns {mat3} out + */ +export function subtract(out, a, b) { + out[0] = a[0] - b[0]; + out[1] = a[1] - b[1]; + out[2] = a[2] - b[2]; + out[3] = a[3] - b[3]; + out[4] = a[4] - b[4]; + out[5] = a[5] - b[5]; + out[6] = a[6] - b[6]; + out[7] = a[7] - b[7]; + out[8] = a[8] - b[8]; + return out; +} + + + +/** + * Multiply each element of the matrix by a scalar. + * + * @param {mat3} out the receiving matrix + * @param {mat3} a the matrix to scale + * @param {Number} b amount to scale the matrix's elements by + * @returns {mat3} out + */ +export function multiplyScalar(out, a, b) { + out[0] = a[0] * b; + out[1] = a[1] * b; + out[2] = a[2] * b; + out[3] = a[3] * b; + out[4] = a[4] * b; + out[5] = a[5] * b; + out[6] = a[6] * b; + out[7] = a[7] * b; + out[8] = a[8] * b; + return out; +} + +/** + * Adds two mat3's after multiplying each element of the second operand by a scalar value. + * + * @param {mat3} out the receiving vector + * @param {mat3} a the first operand + * @param {mat3} b the second operand + * @param {Number} scale the amount to scale b's elements by before adding + * @returns {mat3} out + */ +export function multiplyScalarAndAdd(out, a, b, scale) { + out[0] = a[0] + (b[0] * scale); + out[1] = a[1] + (b[1] * scale); + out[2] = a[2] + (b[2] * scale); + out[3] = a[3] + (b[3] * scale); + out[4] = a[4] + (b[4] * scale); + out[5] = a[5] + (b[5] * scale); + out[6] = a[6] + (b[6] * scale); + out[7] = a[7] + (b[7] * scale); + out[8] = a[8] + (b[8] * scale); + return out; +} + +/** + * Returns whether or not the matrices have exactly the same elements in the same position (when compared with ===) + * + * @param {mat3} a The first matrix. + * @param {mat3} b The second matrix. + * @returns {Boolean} True if the matrices are equal, false otherwise. + */ +export function exactEquals(a, b) { + return a[0] === b[0] && a[1] === b[1] && a[2] === b[2] && + a[3] === b[3] && a[4] === b[4] && a[5] === b[5] && + a[6] === b[6] && a[7] === b[7] && a[8] === b[8]; +} + +/** + * Returns whether or not the matrices have approximately the same elements in the same position. + * + * @param {mat3} a The first matrix. + * @param {mat3} b The second matrix. + * @returns {Boolean} True if the matrices are equal, false otherwise. + */ +export function equals(a, b) { + let a0 = a[0], a1 = a[1], a2 = a[2], a3 = a[3], a4 = a[4], a5 = a[5], a6 = a[6], a7 = a[7], a8 = a[8]; + let b0 = b[0], b1 = b[1], b2 = b[2], b3 = b[3], b4 = b[4], b5 = b[5], b6 = b[6], b7 = b[7], b8 = b[8]; + return (Math.abs(a0 - b0) <= glMatrix.EPSILON*Math.max(1.0, Math.abs(a0), Math.abs(b0)) && + Math.abs(a1 - b1) <= glMatrix.EPSILON*Math.max(1.0, Math.abs(a1), Math.abs(b1)) && + Math.abs(a2 - b2) <= glMatrix.EPSILON*Math.max(1.0, Math.abs(a2), Math.abs(b2)) && + Math.abs(a3 - b3) <= glMatrix.EPSILON*Math.max(1.0, Math.abs(a3), Math.abs(b3)) && + Math.abs(a4 - b4) <= glMatrix.EPSILON*Math.max(1.0, Math.abs(a4), Math.abs(b4)) && + Math.abs(a5 - b5) <= glMatrix.EPSILON*Math.max(1.0, Math.abs(a5), Math.abs(b5)) && + Math.abs(a6 - b6) <= glMatrix.EPSILON*Math.max(1.0, Math.abs(a6), Math.abs(b6)) && + Math.abs(a7 - b7) <= glMatrix.EPSILON*Math.max(1.0, Math.abs(a7), Math.abs(b7)) && + Math.abs(a8 - b8) <= glMatrix.EPSILON*Math.max(1.0, Math.abs(a8), Math.abs(b8))); +} + +/** + * Alias for {@link mat3.multiply} + * @function + */ +export const mul = multiply; + +/** + * Alias for {@link mat3.subtract} + * @function + */ +export const sub = subtract; diff --git a/src/globe/beam/glMatrix/mat4.js b/src/globe/beam/glMatrix/mat4.js new file mode 100755 index 0000000..ac79985 --- /dev/null +++ b/src/globe/beam/glMatrix/mat4.js @@ -0,0 +1,1681 @@ +/* Copyright (c) 2015, Brandon Jones, Colin MacKenzie IV. + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. */ + +import * as glMatrix from "./common"; + +/** + * 4x4 Matrix + * @module mat4 + */ + +/** + * Creates a new identity mat4 + * + * @returns {mat4} a new 4x4 matrix + */ +export function create() { + let out = new glMatrix.ARRAY_TYPE(16); + out[0] = 1; + out[1] = 0; + out[2] = 0; + out[3] = 0; + out[4] = 0; + out[5] = 1; + out[6] = 0; + out[7] = 0; + out[8] = 0; + out[9] = 0; + out[10] = 1; + out[11] = 0; + out[12] = 0; + out[13] = 0; + out[14] = 0; + out[15] = 1; + return out; +} + +/** + * Creates a new mat4 initialized with values from an existing matrix + * + * @param {mat4} a matrix to clone + * @returns {mat4} a new 4x4 matrix + */ +export function clone(a) { + let out = new glMatrix.ARRAY_TYPE(16); + out[0] = a[0]; + out[1] = a[1]; + out[2] = a[2]; + out[3] = a[3]; + out[4] = a[4]; + out[5] = a[5]; + out[6] = a[6]; + out[7] = a[7]; + out[8] = a[8]; + out[9] = a[9]; + out[10] = a[10]; + out[11] = a[11]; + out[12] = a[12]; + out[13] = a[13]; + out[14] = a[14]; + out[15] = a[15]; + return out; +} + +/** + * Copy the values from one mat4 to another + * + * @param {mat4} out the receiving matrix + * @param {mat4} a the source matrix + * @returns {mat4} out + */ +export function copy(out, a) { + out[0] = a[0]; + out[1] = a[1]; + out[2] = a[2]; + out[3] = a[3]; + out[4] = a[4]; + out[5] = a[5]; + out[6] = a[6]; + out[7] = a[7]; + out[8] = a[8]; + out[9] = a[9]; + out[10] = a[10]; + out[11] = a[11]; + out[12] = a[12]; + out[13] = a[13]; + out[14] = a[14]; + out[15] = a[15]; + return out; +} + +/** + * Create a new mat4 with the given values + * + * @param {Number} m00 Component in column 0, row 0 position (index 0) + * @param {Number} m01 Component in column 0, row 1 position (index 1) + * @param {Number} m02 Component in column 0, row 2 position (index 2) + * @param {Number} m03 Component in column 0, row 3 position (index 3) + * @param {Number} m10 Component in column 1, row 0 position (index 4) + * @param {Number} m11 Component in column 1, row 1 position (index 5) + * @param {Number} m12 Component in column 1, row 2 position (index 6) + * @param {Number} m13 Component in column 1, row 3 position (index 7) + * @param {Number} m20 Component in column 2, row 0 position (index 8) + * @param {Number} m21 Component in column 2, row 1 position (index 9) + * @param {Number} m22 Component in column 2, row 2 position (index 10) + * @param {Number} m23 Component in column 2, row 3 position (index 11) + * @param {Number} m30 Component in column 3, row 0 position (index 12) + * @param {Number} m31 Component in column 3, row 1 position (index 13) + * @param {Number} m32 Component in column 3, row 2 position (index 14) + * @param {Number} m33 Component in column 3, row 3 position (index 15) + * @returns {mat4} A new mat4 + */ +export function fromValues(m00, m01, m02, m03, m10, m11, m12, m13, m20, m21, m22, m23, m30, m31, m32, m33) { + let out = new glMatrix.ARRAY_TYPE(16); + out[0] = m00; + out[1] = m01; + out[2] = m02; + out[3] = m03; + out[4] = m10; + out[5] = m11; + out[6] = m12; + out[7] = m13; + out[8] = m20; + out[9] = m21; + out[10] = m22; + out[11] = m23; + out[12] = m30; + out[13] = m31; + out[14] = m32; + out[15] = m33; + return out; +} + +/** + * Set the components of a mat4 to the given values + * + * @param {mat4} out the receiving matrix + * @param {Number} m00 Component in column 0, row 0 position (index 0) + * @param {Number} m01 Component in column 0, row 1 position (index 1) + * @param {Number} m02 Component in column 0, row 2 position (index 2) + * @param {Number} m03 Component in column 0, row 3 position (index 3) + * @param {Number} m10 Component in column 1, row 0 position (index 4) + * @param {Number} m11 Component in column 1, row 1 position (index 5) + * @param {Number} m12 Component in column 1, row 2 position (index 6) + * @param {Number} m13 Component in column 1, row 3 position (index 7) + * @param {Number} m20 Component in column 2, row 0 position (index 8) + * @param {Number} m21 Component in column 2, row 1 position (index 9) + * @param {Number} m22 Component in column 2, row 2 position (index 10) + * @param {Number} m23 Component in column 2, row 3 position (index 11) + * @param {Number} m30 Component in column 3, row 0 position (index 12) + * @param {Number} m31 Component in column 3, row 1 position (index 13) + * @param {Number} m32 Component in column 3, row 2 position (index 14) + * @param {Number} m33 Component in column 3, row 3 position (index 15) + * @returns {mat4} out + */ +export function set(out, m00, m01, m02, m03, m10, m11, m12, m13, m20, m21, m22, m23, m30, m31, m32, m33) { + out[0] = m00; + out[1] = m01; + out[2] = m02; + out[3] = m03; + out[4] = m10; + out[5] = m11; + out[6] = m12; + out[7] = m13; + out[8] = m20; + out[9] = m21; + out[10] = m22; + out[11] = m23; + out[12] = m30; + out[13] = m31; + out[14] = m32; + out[15] = m33; + return out; +} + + +/** + * Set a mat4 to the identity matrix + * + * @param {mat4} out the receiving matrix + * @returns {mat4} out + */ +export function identity(out) { + out[0] = 1; + out[1] = 0; + out[2] = 0; + out[3] = 0; + out[4] = 0; + out[5] = 1; + out[6] = 0; + out[7] = 0; + out[8] = 0; + out[9] = 0; + out[10] = 1; + out[11] = 0; + out[12] = 0; + out[13] = 0; + out[14] = 0; + out[15] = 1; + return out; +} + +/** + * Transpose the values of a mat4 + * + * @param {mat4} out the receiving matrix + * @param {mat4} a the source matrix + * @returns {mat4} out + */ +export function transpose(out, a) { + // If we are transposing ourselves we can skip a few steps but have to cache some values + if (out === a) { + let a01 = a[1], a02 = a[2], a03 = a[3]; + let a12 = a[6], a13 = a[7]; + let a23 = a[11]; + + out[1] = a[4]; + out[2] = a[8]; + out[3] = a[12]; + out[4] = a01; + out[6] = a[9]; + out[7] = a[13]; + out[8] = a02; + out[9] = a12; + out[11] = a[14]; + out[12] = a03; + out[13] = a13; + out[14] = a23; + } else { + out[0] = a[0]; + out[1] = a[4]; + out[2] = a[8]; + out[3] = a[12]; + out[4] = a[1]; + out[5] = a[5]; + out[6] = a[9]; + out[7] = a[13]; + out[8] = a[2]; + out[9] = a[6]; + out[10] = a[10]; + out[11] = a[14]; + out[12] = a[3]; + out[13] = a[7]; + out[14] = a[11]; + out[15] = a[15]; + } + + return out; +} + +/** + * Inverts a mat4 + * + * @param {mat4} out the receiving matrix + * @param {mat4} a the source matrix + * @returns {mat4} out + */ +export function invert(out, a) { + let a00 = a[0], a01 = a[1], a02 = a[2], a03 = a[3]; + let a10 = a[4], a11 = a[5], a12 = a[6], a13 = a[7]; + let a20 = a[8], a21 = a[9], a22 = a[10], a23 = a[11]; + let a30 = a[12], a31 = a[13], a32 = a[14], a33 = a[15]; + + let b00 = a00 * a11 - a01 * a10; + let b01 = a00 * a12 - a02 * a10; + let b02 = a00 * a13 - a03 * a10; + let b03 = a01 * a12 - a02 * a11; + let b04 = a01 * a13 - a03 * a11; + let b05 = a02 * a13 - a03 * a12; + let b06 = a20 * a31 - a21 * a30; + let b07 = a20 * a32 - a22 * a30; + let b08 = a20 * a33 - a23 * a30; + let b09 = a21 * a32 - a22 * a31; + let b10 = a21 * a33 - a23 * a31; + let b11 = a22 * a33 - a23 * a32; + + // Calculate the determinant + let det = b00 * b11 - b01 * b10 + b02 * b09 + b03 * b08 - b04 * b07 + b05 * b06; + + if (!det) { + return null; + } + det = 1.0 / det; + + out[0] = (a11 * b11 - a12 * b10 + a13 * b09) * det; + out[1] = (a02 * b10 - a01 * b11 - a03 * b09) * det; + out[2] = (a31 * b05 - a32 * b04 + a33 * b03) * det; + out[3] = (a22 * b04 - a21 * b05 - a23 * b03) * det; + out[4] = (a12 * b08 - a10 * b11 - a13 * b07) * det; + out[5] = (a00 * b11 - a02 * b08 + a03 * b07) * det; + out[6] = (a32 * b02 - a30 * b05 - a33 * b01) * det; + out[7] = (a20 * b05 - a22 * b02 + a23 * b01) * det; + out[8] = (a10 * b10 - a11 * b08 + a13 * b06) * det; + out[9] = (a01 * b08 - a00 * b10 - a03 * b06) * det; + out[10] = (a30 * b04 - a31 * b02 + a33 * b00) * det; + out[11] = (a21 * b02 - a20 * b04 - a23 * b00) * det; + out[12] = (a11 * b07 - a10 * b09 - a12 * b06) * det; + out[13] = (a00 * b09 - a01 * b07 + a02 * b06) * det; + out[14] = (a31 * b01 - a30 * b03 - a32 * b00) * det; + out[15] = (a20 * b03 - a21 * b01 + a22 * b00) * det; + + return out; +} + +/** + * Calculates the adjugate of a mat4 + * + * @param {mat4} out the receiving matrix + * @param {mat4} a the source matrix + * @returns {mat4} out + */ +export function adjoint(out, a) { + let a00 = a[0], a01 = a[1], a02 = a[2], a03 = a[3]; + let a10 = a[4], a11 = a[5], a12 = a[6], a13 = a[7]; + let a20 = a[8], a21 = a[9], a22 = a[10], a23 = a[11]; + let a30 = a[12], a31 = a[13], a32 = a[14], a33 = a[15]; + + out[0] = (a11 * (a22 * a33 - a23 * a32) - a21 * (a12 * a33 - a13 * a32) + a31 * (a12 * a23 - a13 * a22)); + out[1] = -(a01 * (a22 * a33 - a23 * a32) - a21 * (a02 * a33 - a03 * a32) + a31 * (a02 * a23 - a03 * a22)); + out[2] = (a01 * (a12 * a33 - a13 * a32) - a11 * (a02 * a33 - a03 * a32) + a31 * (a02 * a13 - a03 * a12)); + out[3] = -(a01 * (a12 * a23 - a13 * a22) - a11 * (a02 * a23 - a03 * a22) + a21 * (a02 * a13 - a03 * a12)); + out[4] = -(a10 * (a22 * a33 - a23 * a32) - a20 * (a12 * a33 - a13 * a32) + a30 * (a12 * a23 - a13 * a22)); + out[5] = (a00 * (a22 * a33 - a23 * a32) - a20 * (a02 * a33 - a03 * a32) + a30 * (a02 * a23 - a03 * a22)); + out[6] = -(a00 * (a12 * a33 - a13 * a32) - a10 * (a02 * a33 - a03 * a32) + a30 * (a02 * a13 - a03 * a12)); + out[7] = (a00 * (a12 * a23 - a13 * a22) - a10 * (a02 * a23 - a03 * a22) + a20 * (a02 * a13 - a03 * a12)); + out[8] = (a10 * (a21 * a33 - a23 * a31) - a20 * (a11 * a33 - a13 * a31) + a30 * (a11 * a23 - a13 * a21)); + out[9] = -(a00 * (a21 * a33 - a23 * a31) - a20 * (a01 * a33 - a03 * a31) + a30 * (a01 * a23 - a03 * a21)); + out[10] = (a00 * (a11 * a33 - a13 * a31) - a10 * (a01 * a33 - a03 * a31) + a30 * (a01 * a13 - a03 * a11)); + out[11] = -(a00 * (a11 * a23 - a13 * a21) - a10 * (a01 * a23 - a03 * a21) + a20 * (a01 * a13 - a03 * a11)); + out[12] = -(a10 * (a21 * a32 - a22 * a31) - a20 * (a11 * a32 - a12 * a31) + a30 * (a11 * a22 - a12 * a21)); + out[13] = (a00 * (a21 * a32 - a22 * a31) - a20 * (a01 * a32 - a02 * a31) + a30 * (a01 * a22 - a02 * a21)); + out[14] = -(a00 * (a11 * a32 - a12 * a31) - a10 * (a01 * a32 - a02 * a31) + a30 * (a01 * a12 - a02 * a11)); + out[15] = (a00 * (a11 * a22 - a12 * a21) - a10 * (a01 * a22 - a02 * a21) + a20 * (a01 * a12 - a02 * a11)); + return out; +} + +/** + * Calculates the determinant of a mat4 + * + * @param {mat4} a the source matrix + * @returns {Number} determinant of a + */ +export function determinant(a) { + let a00 = a[0], a01 = a[1], a02 = a[2], a03 = a[3]; + let a10 = a[4], a11 = a[5], a12 = a[6], a13 = a[7]; + let a20 = a[8], a21 = a[9], a22 = a[10], a23 = a[11]; + let a30 = a[12], a31 = a[13], a32 = a[14], a33 = a[15]; + + let b00 = a00 * a11 - a01 * a10; + let b01 = a00 * a12 - a02 * a10; + let b02 = a00 * a13 - a03 * a10; + let b03 = a01 * a12 - a02 * a11; + let b04 = a01 * a13 - a03 * a11; + let b05 = a02 * a13 - a03 * a12; + let b06 = a20 * a31 - a21 * a30; + let b07 = a20 * a32 - a22 * a30; + let b08 = a20 * a33 - a23 * a30; + let b09 = a21 * a32 - a22 * a31; + let b10 = a21 * a33 - a23 * a31; + let b11 = a22 * a33 - a23 * a32; + + // Calculate the determinant + return b00 * b11 - b01 * b10 + b02 * b09 + b03 * b08 - b04 * b07 + b05 * b06; +} + +/** + * Multiplies two mat4s + * + * @param {mat4} out the receiving matrix + * @param {mat4} a the first operand + * @param {mat4} b the second operand + * @returns {mat4} out + */ +export function multiply(out, a, b) { + let a00 = a[0], a01 = a[1], a02 = a[2], a03 = a[3]; + let a10 = a[4], a11 = a[5], a12 = a[6], a13 = a[7]; + let a20 = a[8], a21 = a[9], a22 = a[10], a23 = a[11]; + let a30 = a[12], a31 = a[13], a32 = a[14], a33 = a[15]; + + // Cache only the current line of the second matrix + let b0 = b[0], b1 = b[1], b2 = b[2], b3 = b[3]; + out[0] = b0*a00 + b1*a10 + b2*a20 + b3*a30; + out[1] = b0*a01 + b1*a11 + b2*a21 + b3*a31; + out[2] = b0*a02 + b1*a12 + b2*a22 + b3*a32; + out[3] = b0*a03 + b1*a13 + b2*a23 + b3*a33; + + b0 = b[4]; b1 = b[5]; b2 = b[6]; b3 = b[7]; + out[4] = b0*a00 + b1*a10 + b2*a20 + b3*a30; + out[5] = b0*a01 + b1*a11 + b2*a21 + b3*a31; + out[6] = b0*a02 + b1*a12 + b2*a22 + b3*a32; + out[7] = b0*a03 + b1*a13 + b2*a23 + b3*a33; + + b0 = b[8]; b1 = b[9]; b2 = b[10]; b3 = b[11]; + out[8] = b0*a00 + b1*a10 + b2*a20 + b3*a30; + out[9] = b0*a01 + b1*a11 + b2*a21 + b3*a31; + out[10] = b0*a02 + b1*a12 + b2*a22 + b3*a32; + out[11] = b0*a03 + b1*a13 + b2*a23 + b3*a33; + + b0 = b[12]; b1 = b[13]; b2 = b[14]; b3 = b[15]; + out[12] = b0*a00 + b1*a10 + b2*a20 + b3*a30; + out[13] = b0*a01 + b1*a11 + b2*a21 + b3*a31; + out[14] = b0*a02 + b1*a12 + b2*a22 + b3*a32; + out[15] = b0*a03 + b1*a13 + b2*a23 + b3*a33; + return out; +} + +/** + * Translate a mat4 by the given vector + * + * @param {mat4} out the receiving matrix + * @param {mat4} a the matrix to translate + * @param {vec3} v vector to translate by + * @returns {mat4} out + */ +export function translate(out, a, v) { + let x = v[0], y = v[1], z = v[2]; + let a00, a01, a02, a03; + let a10, a11, a12, a13; + let a20, a21, a22, a23; + + if (a === out) { + out[12] = a[0] * x + a[4] * y + a[8] * z + a[12]; + out[13] = a[1] * x + a[5] * y + a[9] * z + a[13]; + out[14] = a[2] * x + a[6] * y + a[10] * z + a[14]; + out[15] = a[3] * x + a[7] * y + a[11] * z + a[15]; + } else { + a00 = a[0]; a01 = a[1]; a02 = a[2]; a03 = a[3]; + a10 = a[4]; a11 = a[5]; a12 = a[6]; a13 = a[7]; + a20 = a[8]; a21 = a[9]; a22 = a[10]; a23 = a[11]; + + out[0] = a00; out[1] = a01; out[2] = a02; out[3] = a03; + out[4] = a10; out[5] = a11; out[6] = a12; out[7] = a13; + out[8] = a20; out[9] = a21; out[10] = a22; out[11] = a23; + + out[12] = a00 * x + a10 * y + a20 * z + a[12]; + out[13] = a01 * x + a11 * y + a21 * z + a[13]; + out[14] = a02 * x + a12 * y + a22 * z + a[14]; + out[15] = a03 * x + a13 * y + a23 * z + a[15]; + } + + return out; +} + +/** + * Scales the mat4 by the dimensions in the given vec3 not using vectorization + * + * @param {mat4} out the receiving matrix + * @param {mat4} a the matrix to scale + * @param {vec3} v the vec3 to scale the matrix by + * @returns {mat4} out + **/ +export function scale(out, a, v) { + let x = v[0], y = v[1], z = v[2]; + + out[0] = a[0] * x; + out[1] = a[1] * x; + out[2] = a[2] * x; + out[3] = a[3] * x; + out[4] = a[4] * y; + out[5] = a[5] * y; + out[6] = a[6] * y; + out[7] = a[7] * y; + out[8] = a[8] * z; + out[9] = a[9] * z; + out[10] = a[10] * z; + out[11] = a[11] * z; + out[12] = a[12]; + out[13] = a[13]; + out[14] = a[14]; + out[15] = a[15]; + return out; +} + +/** + * Rotates a mat4 by the given angle around the given axis + * + * @param {mat4} out the receiving matrix + * @param {mat4} a the matrix to rotate + * @param {Number} rad the angle to rotate the matrix by + * @param {vec3} axis the axis to rotate around + * @returns {mat4} out + */ +export function rotate(out, a, rad, axis) { + let x = axis[0], y = axis[1], z = axis[2]; + let len = Math.sqrt(x * x + y * y + z * z); + let s, c, t; + let a00, a01, a02, a03; + let a10, a11, a12, a13; + let a20, a21, a22, a23; + let b00, b01, b02; + let b10, b11, b12; + let b20, b21, b22; + + if (Math.abs(len) < glMatrix.EPSILON) { return null; } + + len = 1 / len; + x *= len; + y *= len; + z *= len; + + s = Math.sin(rad); + c = Math.cos(rad); + t = 1 - c; + + a00 = a[0]; a01 = a[1]; a02 = a[2]; a03 = a[3]; + a10 = a[4]; a11 = a[5]; a12 = a[6]; a13 = a[7]; + a20 = a[8]; a21 = a[9]; a22 = a[10]; a23 = a[11]; + + // Construct the elements of the rotation matrix + b00 = x * x * t + c; b01 = y * x * t + z * s; b02 = z * x * t - y * s; + b10 = x * y * t - z * s; b11 = y * y * t + c; b12 = z * y * t + x * s; + b20 = x * z * t + y * s; b21 = y * z * t - x * s; b22 = z * z * t + c; + + // Perform rotation-specific matrix multiplication + out[0] = a00 * b00 + a10 * b01 + a20 * b02; + out[1] = a01 * b00 + a11 * b01 + a21 * b02; + out[2] = a02 * b00 + a12 * b01 + a22 * b02; + out[3] = a03 * b00 + a13 * b01 + a23 * b02; + out[4] = a00 * b10 + a10 * b11 + a20 * b12; + out[5] = a01 * b10 + a11 * b11 + a21 * b12; + out[6] = a02 * b10 + a12 * b11 + a22 * b12; + out[7] = a03 * b10 + a13 * b11 + a23 * b12; + out[8] = a00 * b20 + a10 * b21 + a20 * b22; + out[9] = a01 * b20 + a11 * b21 + a21 * b22; + out[10] = a02 * b20 + a12 * b21 + a22 * b22; + out[11] = a03 * b20 + a13 * b21 + a23 * b22; + + if (a !== out) { // If the source and destination differ, copy the unchanged last row + out[12] = a[12]; + out[13] = a[13]; + out[14] = a[14]; + out[15] = a[15]; + } + return out; +} + +/** + * Rotates a matrix by the given angle around the X axis + * + * @param {mat4} out the receiving matrix + * @param {mat4} a the matrix to rotate + * @param {Number} rad the angle to rotate the matrix by + * @returns {mat4} out + */ +export function rotateX(out, a, rad) { + let s = Math.sin(rad); + let c = Math.cos(rad); + let a10 = a[4]; + let a11 = a[5]; + let a12 = a[6]; + let a13 = a[7]; + let a20 = a[8]; + let a21 = a[9]; + let a22 = a[10]; + let a23 = a[11]; + + if (a !== out) { // If the source and destination differ, copy the unchanged rows + out[0] = a[0]; + out[1] = a[1]; + out[2] = a[2]; + out[3] = a[3]; + out[12] = a[12]; + out[13] = a[13]; + out[14] = a[14]; + out[15] = a[15]; + } + + // Perform axis-specific matrix multiplication + out[4] = a10 * c + a20 * s; + out[5] = a11 * c + a21 * s; + out[6] = a12 * c + a22 * s; + out[7] = a13 * c + a23 * s; + out[8] = a20 * c - a10 * s; + out[9] = a21 * c - a11 * s; + out[10] = a22 * c - a12 * s; + out[11] = a23 * c - a13 * s; + return out; +} + +/** + * Rotates a matrix by the given angle around the Y axis + * + * @param {mat4} out the receiving matrix + * @param {mat4} a the matrix to rotate + * @param {Number} rad the angle to rotate the matrix by + * @returns {mat4} out + */ +export function rotateY(out, a, rad) { + let s = Math.sin(rad); + let c = Math.cos(rad); + let a00 = a[0]; + let a01 = a[1]; + let a02 = a[2]; + let a03 = a[3]; + let a20 = a[8]; + let a21 = a[9]; + let a22 = a[10]; + let a23 = a[11]; + + if (a !== out) { // If the source and destination differ, copy the unchanged rows + out[4] = a[4]; + out[5] = a[5]; + out[6] = a[6]; + out[7] = a[7]; + out[12] = a[12]; + out[13] = a[13]; + out[14] = a[14]; + out[15] = a[15]; + } + + // Perform axis-specific matrix multiplication + out[0] = a00 * c - a20 * s; + out[1] = a01 * c - a21 * s; + out[2] = a02 * c - a22 * s; + out[3] = a03 * c - a23 * s; + out[8] = a00 * s + a20 * c; + out[9] = a01 * s + a21 * c; + out[10] = a02 * s + a22 * c; + out[11] = a03 * s + a23 * c; + return out; +} + +/** + * Rotates a matrix by the given angle around the Z axis + * + * @param {mat4} out the receiving matrix + * @param {mat4} a the matrix to rotate + * @param {Number} rad the angle to rotate the matrix by + * @returns {mat4} out + */ +export function rotateZ(out, a, rad) { + let s = Math.sin(rad); + let c = Math.cos(rad); + let a00 = a[0]; + let a01 = a[1]; + let a02 = a[2]; + let a03 = a[3]; + let a10 = a[4]; + let a11 = a[5]; + let a12 = a[6]; + let a13 = a[7]; + + if (a !== out) { // If the source and destination differ, copy the unchanged last row + out[8] = a[8]; + out[9] = a[9]; + out[10] = a[10]; + out[11] = a[11]; + out[12] = a[12]; + out[13] = a[13]; + out[14] = a[14]; + out[15] = a[15]; + } + + // Perform axis-specific matrix multiplication + out[0] = a00 * c + a10 * s; + out[1] = a01 * c + a11 * s; + out[2] = a02 * c + a12 * s; + out[3] = a03 * c + a13 * s; + out[4] = a10 * c - a00 * s; + out[5] = a11 * c - a01 * s; + out[6] = a12 * c - a02 * s; + out[7] = a13 * c - a03 * s; + return out; +} + +/** + * Creates a matrix from a vector translation + * This is equivalent to (but much faster than): + * + * mat4.identity(dest); + * mat4.translate(dest, dest, vec); + * + * @param {mat4} out mat4 receiving operation result + * @param {vec3} v Translation vector + * @returns {mat4} out + */ +export function fromTranslation(out, v) { + out[0] = 1; + out[1] = 0; + out[2] = 0; + out[3] = 0; + out[4] = 0; + out[5] = 1; + out[6] = 0; + out[7] = 0; + out[8] = 0; + out[9] = 0; + out[10] = 1; + out[11] = 0; + out[12] = v[0]; + out[13] = v[1]; + out[14] = v[2]; + out[15] = 1; + return out; +} + +/** + * Creates a matrix from a vector scaling + * This is equivalent to (but much faster than): + * + * mat4.identity(dest); + * mat4.scale(dest, dest, vec); + * + * @param {mat4} out mat4 receiving operation result + * @param {vec3} v Scaling vector + * @returns {mat4} out + */ +export function fromScaling(out, v) { + out[0] = v[0]; + out[1] = 0; + out[2] = 0; + out[3] = 0; + out[4] = 0; + out[5] = v[1]; + out[6] = 0; + out[7] = 0; + out[8] = 0; + out[9] = 0; + out[10] = v[2]; + out[11] = 0; + out[12] = 0; + out[13] = 0; + out[14] = 0; + out[15] = 1; + return out; +} + +/** + * Creates a matrix from a given angle around a given axis + * This is equivalent to (but much faster than): + * + * mat4.identity(dest); + * mat4.rotate(dest, dest, rad, axis); + * + * @param {mat4} out mat4 receiving operation result + * @param {Number} rad the angle to rotate the matrix by + * @param {vec3} axis the axis to rotate around + * @returns {mat4} out + */ +export function fromRotation(out, rad, axis) { + let x = axis[0], y = axis[1], z = axis[2]; + let len = Math.sqrt(x * x + y * y + z * z); + let s, c, t; + + if (Math.abs(len) < glMatrix.EPSILON) { return null; } + + len = 1 / len; + x *= len; + y *= len; + z *= len; + + s = Math.sin(rad); + c = Math.cos(rad); + t = 1 - c; + + // Perform rotation-specific matrix multiplication + out[0] = x * x * t + c; + out[1] = y * x * t + z * s; + out[2] = z * x * t - y * s; + out[3] = 0; + out[4] = x * y * t - z * s; + out[5] = y * y * t + c; + out[6] = z * y * t + x * s; + out[7] = 0; + out[8] = x * z * t + y * s; + out[9] = y * z * t - x * s; + out[10] = z * z * t + c; + out[11] = 0; + out[12] = 0; + out[13] = 0; + out[14] = 0; + out[15] = 1; + return out; +} + +/** + * Creates a matrix from the given angle around the X axis + * This is equivalent to (but much faster than): + * + * mat4.identity(dest); + * mat4.rotateX(dest, dest, rad); + * + * @param {mat4} out mat4 receiving operation result + * @param {Number} rad the angle to rotate the matrix by + * @returns {mat4} out + */ +export function fromXRotation(out, rad) { + let s = Math.sin(rad); + let c = Math.cos(rad); + + // Perform axis-specific matrix multiplication + out[0] = 1; + out[1] = 0; + out[2] = 0; + out[3] = 0; + out[4] = 0; + out[5] = c; + out[6] = s; + out[7] = 0; + out[8] = 0; + out[9] = -s; + out[10] = c; + out[11] = 0; + out[12] = 0; + out[13] = 0; + out[14] = 0; + out[15] = 1; + return out; +} + +/** + * Creates a matrix from the given angle around the Y axis + * This is equivalent to (but much faster than): + * + * mat4.identity(dest); + * mat4.rotateY(dest, dest, rad); + * + * @param {mat4} out mat4 receiving operation result + * @param {Number} rad the angle to rotate the matrix by + * @returns {mat4} out + */ +export function fromYRotation(out, rad) { + let s = Math.sin(rad); + let c = Math.cos(rad); + + // Perform axis-specific matrix multiplication + out[0] = c; + out[1] = 0; + out[2] = -s; + out[3] = 0; + out[4] = 0; + out[5] = 1; + out[6] = 0; + out[7] = 0; + out[8] = s; + out[9] = 0; + out[10] = c; + out[11] = 0; + out[12] = 0; + out[13] = 0; + out[14] = 0; + out[15] = 1; + return out; +} + +/** + * Creates a matrix from the given angle around the Z axis + * This is equivalent to (but much faster than): + * + * mat4.identity(dest); + * mat4.rotateZ(dest, dest, rad); + * + * @param {mat4} out mat4 receiving operation result + * @param {Number} rad the angle to rotate the matrix by + * @returns {mat4} out + */ +export function fromZRotation(out, rad) { + let s = Math.sin(rad); + let c = Math.cos(rad); + + // Perform axis-specific matrix multiplication + out[0] = c; + out[1] = s; + out[2] = 0; + out[3] = 0; + out[4] = -s; + out[5] = c; + out[6] = 0; + out[7] = 0; + out[8] = 0; + out[9] = 0; + out[10] = 1; + out[11] = 0; + out[12] = 0; + out[13] = 0; + out[14] = 0; + out[15] = 1; + return out; +} + +/** + * Creates a matrix from a quaternion rotation and vector translation + * This is equivalent to (but much faster than): + * + * mat4.identity(dest); + * mat4.translate(dest, vec); + * let quatMat = mat4.create(); + * quat4.toMat4(quat, quatMat); + * mat4.multiply(dest, quatMat); + * + * @param {mat4} out mat4 receiving operation result + * @param {quat4} q Rotation quaternion + * @param {vec3} v Translation vector + * @returns {mat4} out + */ +export function fromRotationTranslation(out, q, v) { + // Quaternion math + let x = q[0], y = q[1], z = q[2], w = q[3]; + let x2 = x + x; + let y2 = y + y; + let z2 = z + z; + + let xx = x * x2; + let xy = x * y2; + let xz = x * z2; + let yy = y * y2; + let yz = y * z2; + let zz = z * z2; + let wx = w * x2; + let wy = w * y2; + let wz = w * z2; + + out[0] = 1 - (yy + zz); + out[1] = xy + wz; + out[2] = xz - wy; + out[3] = 0; + out[4] = xy - wz; + out[5] = 1 - (xx + zz); + out[6] = yz + wx; + out[7] = 0; + out[8] = xz + wy; + out[9] = yz - wx; + out[10] = 1 - (xx + yy); + out[11] = 0; + out[12] = v[0]; + out[13] = v[1]; + out[14] = v[2]; + out[15] = 1; + + return out; +} + +/** + * Returns the translation vector component of a transformation + * matrix. If a matrix is built with fromRotationTranslation, + * the returned vector will be the same as the translation vector + * originally supplied. + * @param {vec3} out Vector to receive translation component + * @param {mat4} mat Matrix to be decomposed (input) + * @return {vec3} out + */ +export function getTranslation(out, mat) { + out[0] = mat[12]; + out[1] = mat[13]; + out[2] = mat[14]; + + return out; +} + +/** + * Returns the scaling factor component of a transformation + * matrix. If a matrix is built with fromRotationTranslationScale + * with a normalized Quaternion paramter, the returned vector will be + * the same as the scaling vector + * originally supplied. + * @param {vec3} out Vector to receive scaling factor component + * @param {mat4} mat Matrix to be decomposed (input) + * @return {vec3} out + */ +export function getScaling(out, mat) { + let m11 = mat[0]; + let m12 = mat[1]; + let m13 = mat[2]; + let m21 = mat[4]; + let m22 = mat[5]; + let m23 = mat[6]; + let m31 = mat[8]; + let m32 = mat[9]; + let m33 = mat[10]; + + out[0] = Math.sqrt(m11 * m11 + m12 * m12 + m13 * m13); + out[1] = Math.sqrt(m21 * m21 + m22 * m22 + m23 * m23); + out[2] = Math.sqrt(m31 * m31 + m32 * m32 + m33 * m33); + + return out; +} + +/** + * Returns a quaternion representing the rotational component + * of a transformation matrix. If a matrix is built with + * fromRotationTranslation, the returned quaternion will be the + * same as the quaternion originally supplied. + * @param {quat} out Quaternion to receive the rotation component + * @param {mat4} mat Matrix to be decomposed (input) + * @return {quat} out + */ +export function getRotation(out, mat) { + // Algorithm taken from http://www.euclideanspace.com/maths/geometry/rotations/conversions/matrixToQuaternion/index.htm + let trace = mat[0] + mat[5] + mat[10]; + let S = 0; + + if (trace > 0) { + S = Math.sqrt(trace + 1.0) * 2; + out[3] = 0.25 * S; + out[0] = (mat[6] - mat[9]) / S; + out[1] = (mat[8] - mat[2]) / S; + out[2] = (mat[1] - mat[4]) / S; + } else if ((mat[0] > mat[5])&(mat[0] > mat[10])) { + S = Math.sqrt(1.0 + mat[0] - mat[5] - mat[10]) * 2; + out[3] = (mat[6] - mat[9]) / S; + out[0] = 0.25 * S; + out[1] = (mat[1] + mat[4]) / S; + out[2] = (mat[8] + mat[2]) / S; + } else if (mat[5] > mat[10]) { + S = Math.sqrt(1.0 + mat[5] - mat[0] - mat[10]) * 2; + out[3] = (mat[8] - mat[2]) / S; + out[0] = (mat[1] + mat[4]) / S; + out[1] = 0.25 * S; + out[2] = (mat[6] + mat[9]) / S; + } else { + S = Math.sqrt(1.0 + mat[10] - mat[0] - mat[5]) * 2; + out[3] = (mat[1] - mat[4]) / S; + out[0] = (mat[8] + mat[2]) / S; + out[1] = (mat[6] + mat[9]) / S; + out[2] = 0.25 * S; + } + + return out; +} + +/** + * Creates a matrix from a quaternion rotation, vector translation and vector scale + * This is equivalent to (but much faster than): + * + * mat4.identity(dest); + * mat4.translate(dest, vec); + * let quatMat = mat4.create(); + * quat4.toMat4(quat, quatMat); + * mat4.multiply(dest, quatMat); + * mat4.scale(dest, scale) + * + * @param {mat4} out mat4 receiving operation result + * @param {quat4} q Rotation quaternion + * @param {vec3} v Translation vector + * @param {vec3} s Scaling vector + * @returns {mat4} out + */ +export function fromRotationTranslationScale(out, q, v, s) { + // Quaternion math + let x = q[0], y = q[1], z = q[2], w = q[3]; + let x2 = x + x; + let y2 = y + y; + let z2 = z + z; + + let xx = x * x2; + let xy = x * y2; + let xz = x * z2; + let yy = y * y2; + let yz = y * z2; + let zz = z * z2; + let wx = w * x2; + let wy = w * y2; + let wz = w * z2; + let sx = s[0]; + let sy = s[1]; + let sz = s[2]; + + out[0] = (1 - (yy + zz)) * sx; + out[1] = (xy + wz) * sx; + out[2] = (xz - wy) * sx; + out[3] = 0; + out[4] = (xy - wz) * sy; + out[5] = (1 - (xx + zz)) * sy; + out[6] = (yz + wx) * sy; + out[7] = 0; + out[8] = (xz + wy) * sz; + out[9] = (yz - wx) * sz; + out[10] = (1 - (xx + yy)) * sz; + out[11] = 0; + out[12] = v[0]; + out[13] = v[1]; + out[14] = v[2]; + out[15] = 1; + + return out; +} + +/** + * Creates a matrix from a quaternion rotation, vector translation and vector scale, rotating and scaling around the given origin + * This is equivalent to (but much faster than): + * + * mat4.identity(dest); + * mat4.translate(dest, vec); + * mat4.translate(dest, origin); + * let quatMat = mat4.create(); + * quat4.toMat4(quat, quatMat); + * mat4.multiply(dest, quatMat); + * mat4.scale(dest, scale) + * mat4.translate(dest, negativeOrigin); + * + * @param {mat4} out mat4 receiving operation result + * @param {quat4} q Rotation quaternion + * @param {vec3} v Translation vector + * @param {vec3} s Scaling vector + * @param {vec3} o The origin vector around which to scale and rotate + * @returns {mat4} out + */ +export function fromRotationTranslationScaleOrigin(out, q, v, s, o) { + // Quaternion math + let x = q[0], y = q[1], z = q[2], w = q[3]; + let x2 = x + x; + let y2 = y + y; + let z2 = z + z; + + let xx = x * x2; + let xy = x * y2; + let xz = x * z2; + let yy = y * y2; + let yz = y * z2; + let zz = z * z2; + let wx = w * x2; + let wy = w * y2; + let wz = w * z2; + + let sx = s[0]; + let sy = s[1]; + let sz = s[2]; + + let ox = o[0]; + let oy = o[1]; + let oz = o[2]; + + out[0] = (1 - (yy + zz)) * sx; + out[1] = (xy + wz) * sx; + out[2] = (xz - wy) * sx; + out[3] = 0; + out[4] = (xy - wz) * sy; + out[5] = (1 - (xx + zz)) * sy; + out[6] = (yz + wx) * sy; + out[7] = 0; + out[8] = (xz + wy) * sz; + out[9] = (yz - wx) * sz; + out[10] = (1 - (xx + yy)) * sz; + out[11] = 0; + out[12] = v[0] + ox - (out[0] * ox + out[4] * oy + out[8] * oz); + out[13] = v[1] + oy - (out[1] * ox + out[5] * oy + out[9] * oz); + out[14] = v[2] + oz - (out[2] * ox + out[6] * oy + out[10] * oz); + out[15] = 1; + + return out; +} + +/** + * Calculates a 4x4 matrix from the given quaternion + * + * @param {mat4} out mat4 receiving operation result + * @param {quat} q Quaternion to create matrix from + * + * @returns {mat4} out + */ +export function fromQuat(out, q) { + let x = q[0], y = q[1], z = q[2], w = q[3]; + let x2 = x + x; + let y2 = y + y; + let z2 = z + z; + + let xx = x * x2; + let yx = y * x2; + let yy = y * y2; + let zx = z * x2; + let zy = z * y2; + let zz = z * z2; + let wx = w * x2; + let wy = w * y2; + let wz = w * z2; + + out[0] = 1 - yy - zz; + out[1] = yx + wz; + out[2] = zx - wy; + out[3] = 0; + + out[4] = yx - wz; + out[5] = 1 - xx - zz; + out[6] = zy + wx; + out[7] = 0; + + out[8] = zx + wy; + out[9] = zy - wx; + out[10] = 1 - xx - yy; + out[11] = 0; + + out[12] = 0; + out[13] = 0; + out[14] = 0; + out[15] = 1; + + return out; +} + +/** + * Generates a frustum matrix with the given bounds + * + * @param {mat4} out mat4 frustum matrix will be written into + * @param {Number} left Left bound of the frustum + * @param {Number} right Right bound of the frustum + * @param {Number} bottom Bottom bound of the frustum + * @param {Number} top Top bound of the frustum + * @param {Number} near Near bound of the frustum + * @param {Number} far Far bound of the frustum + * @returns {mat4} out + */ +export function frustum(out, left, right, bottom, top, near, far) { + let rl = 1 / (right - left); + let tb = 1 / (top - bottom); + let nf = 1 / (near - far); + out[0] = (near * 2) * rl; + out[1] = 0; + out[2] = 0; + out[3] = 0; + out[4] = 0; + out[5] = (near * 2) * tb; + out[6] = 0; + out[7] = 0; + out[8] = (right + left) * rl; + out[9] = (top + bottom) * tb; + out[10] = (far + near) * nf; + out[11] = -1; + out[12] = 0; + out[13] = 0; + out[14] = (far * near * 2) * nf; + out[15] = 0; + return out; +} + +/** + * Generates a perspective projection matrix with the given bounds + * + * @param {mat4} out mat4 frustum matrix will be written into + * @param {number} fovy Vertical field of view in radians + * @param {number} aspect Aspect ratio. typically viewport width/height + * @param {number} near Near bound of the frustum + * @param {number} far Far bound of the frustum + * @returns {mat4} out + */ +export function perspective(out, fovy, aspect, near, far) { + let f = 1.0 / Math.tan(fovy / 2); + let nf = 1 / (near - far); + out[0] = f / aspect; + out[1] = 0; + out[2] = 0; + out[3] = 0; + out[4] = 0; + out[5] = f; + out[6] = 0; + out[7] = 0; + out[8] = 0; + out[9] = 0; + out[10] = (far + near) * nf; + out[11] = -1; + out[12] = 0; + out[13] = 0; + out[14] = (2 * far * near) * nf; + out[15] = 0; + return out; +} + +/** + * Generates a perspective projection matrix with the given field of view. + * This is primarily useful for generating projection matrices to be used + * with the still experiemental WebVR API. + * + * @param {mat4} out mat4 frustum matrix will be written into + * @param {Object} fov Object containing the following values: upDegrees, downDegrees, leftDegrees, rightDegrees + * @param {number} near Near bound of the frustum + * @param {number} far Far bound of the frustum + * @returns {mat4} out + */ +export function perspectiveFromFieldOfView(out, fov, near, far) { + let upTan = Math.tan(fov.upDegrees * Math.PI/180.0); + let downTan = Math.tan(fov.downDegrees * Math.PI/180.0); + let leftTan = Math.tan(fov.leftDegrees * Math.PI/180.0); + let rightTan = Math.tan(fov.rightDegrees * Math.PI/180.0); + let xScale = 2.0 / (leftTan + rightTan); + let yScale = 2.0 / (upTan + downTan); + + out[0] = xScale; + out[1] = 0.0; + out[2] = 0.0; + out[3] = 0.0; + out[4] = 0.0; + out[5] = yScale; + out[6] = 0.0; + out[7] = 0.0; + out[8] = -((leftTan - rightTan) * xScale * 0.5); + out[9] = ((upTan - downTan) * yScale * 0.5); + out[10] = far / (near - far); + out[11] = -1.0; + out[12] = 0.0; + out[13] = 0.0; + out[14] = (far * near) / (near - far); + out[15] = 0.0; + return out; +} + +/** + * Generates a orthogonal projection matrix with the given bounds + * + * @param {mat4} out mat4 frustum matrix will be written into + * @param {number} left Left bound of the frustum + * @param {number} right Right bound of the frustum + * @param {number} bottom Bottom bound of the frustum + * @param {number} top Top bound of the frustum + * @param {number} near Near bound of the frustum + * @param {number} far Far bound of the frustum + * @returns {mat4} out + */ +export function ortho(out, left, right, bottom, top, near, far) { + let lr = 1 / (left - right); + let bt = 1 / (bottom - top); + let nf = 1 / (near - far); + out[0] = -2 * lr; + out[1] = 0; + out[2] = 0; + out[3] = 0; + out[4] = 0; + out[5] = -2 * bt; + out[6] = 0; + out[7] = 0; + out[8] = 0; + out[9] = 0; + out[10] = 2 * nf; + out[11] = 0; + out[12] = (left + right) * lr; + out[13] = (top + bottom) * bt; + out[14] = (far + near) * nf; + out[15] = 1; + return out; +} + +/** + * Generates a look-at matrix with the given eye position, focal point, and up axis + * + * @param {mat4} out mat4 frustum matrix will be written into + * @param {vec3} eye Position of the viewer + * @param {vec3} center Point the viewer is looking at + * @param {vec3} up vec3 pointing up + * @returns {mat4} out + */ +export function lookAt(out, eye, center, up) { + let x0, x1, x2, y0, y1, y2, z0, z1, z2, len; + let eyex = eye[0]; + let eyey = eye[1]; + let eyez = eye[2]; + let upx = up[0]; + let upy = up[1]; + let upz = up[2]; + let centerx = center[0]; + let centery = center[1]; + let centerz = center[2]; + + if (Math.abs(eyex - centerx) < glMatrix.EPSILON && + Math.abs(eyey - centery) < glMatrix.EPSILON && + Math.abs(eyez - centerz) < glMatrix.EPSILON) { + return identity(out); + } + + z0 = eyex - centerx; + z1 = eyey - centery; + z2 = eyez - centerz; + + len = 1 / Math.sqrt(z0 * z0 + z1 * z1 + z2 * z2); + z0 *= len; + z1 *= len; + z2 *= len; + + x0 = upy * z2 - upz * z1; + x1 = upz * z0 - upx * z2; + x2 = upx * z1 - upy * z0; + len = Math.sqrt(x0 * x0 + x1 * x1 + x2 * x2); + if (!len) { + x0 = 0; + x1 = 0; + x2 = 0; + } else { + len = 1 / len; + x0 *= len; + x1 *= len; + x2 *= len; + } + + y0 = z1 * x2 - z2 * x1; + y1 = z2 * x0 - z0 * x2; + y2 = z0 * x1 - z1 * x0; + + len = Math.sqrt(y0 * y0 + y1 * y1 + y2 * y2); + if (!len) { + y0 = 0; + y1 = 0; + y2 = 0; + } else { + len = 1 / len; + y0 *= len; + y1 *= len; + y2 *= len; + } + + out[0] = x0; + out[1] = y0; + out[2] = z0; + out[3] = 0; + out[4] = x1; + out[5] = y1; + out[6] = z1; + out[7] = 0; + out[8] = x2; + out[9] = y2; + out[10] = z2; + out[11] = 0; + out[12] = -(x0 * eyex + x1 * eyey + x2 * eyez); + out[13] = -(y0 * eyex + y1 * eyey + y2 * eyez); + out[14] = -(z0 * eyex + z1 * eyey + z2 * eyez); + out[15] = 1; + + return out; +} + +/** + * Generates a matrix that makes something look at something else. + * + * @param {mat4} out mat4 frustum matrix will be written into + * @param {vec3} eye Position of the viewer + * @param {vec3} center Point the viewer is looking at + * @param {vec3} up vec3 pointing up + * @returns {mat4} out + */ +export function targetTo(out, eye, target, up) { + let eyex = eye[0], + eyey = eye[1], + eyez = eye[2], + upx = up[0], + upy = up[1], + upz = up[2]; + + let z0 = eyex - target[0], + z1 = eyey - target[1], + z2 = eyez - target[2]; + + let len = z0*z0 + z1*z1 + z2*z2; + if (len > 0) { + len = 1 / Math.sqrt(len); + z0 *= len; + z1 *= len; + z2 *= len; + } + + let x0 = upy * z2 - upz * z1, + x1 = upz * z0 - upx * z2, + x2 = upx * z1 - upy * z0; + + out[0] = x0; + out[1] = x1; + out[2] = x2; + out[3] = 0; + out[4] = z1 * x2 - z2 * x1; + out[5] = z2 * x0 - z0 * x2; + out[6] = z0 * x1 - z1 * x0; + out[7] = 0; + out[8] = z0; + out[9] = z1; + out[10] = z2; + out[11] = 0; + out[12] = eyex; + out[13] = eyey; + out[14] = eyez; + out[15] = 1; + return out; +}; + +/** + * Returns a string representation of a mat4 + * + * @param {mat4} a matrix to represent as a string + * @returns {String} string representation of the matrix + */ +export function str(a) { + return 'mat4(' + a[0] + ', ' + a[1] + ', ' + a[2] + ', ' + a[3] + ', ' + + a[4] + ', ' + a[5] + ', ' + a[6] + ', ' + a[7] + ', ' + + a[8] + ', ' + a[9] + ', ' + a[10] + ', ' + a[11] + ', ' + + a[12] + ', ' + a[13] + ', ' + a[14] + ', ' + a[15] + ')'; +} + +/** + * Returns Frobenius norm of a mat4 + * + * @param {mat4} a the matrix to calculate Frobenius norm of + * @returns {Number} Frobenius norm + */ +export function frob(a) { + return(Math.sqrt(Math.pow(a[0], 2) + Math.pow(a[1], 2) + Math.pow(a[2], 2) + Math.pow(a[3], 2) + Math.pow(a[4], 2) + Math.pow(a[5], 2) + Math.pow(a[6], 2) + Math.pow(a[7], 2) + Math.pow(a[8], 2) + Math.pow(a[9], 2) + Math.pow(a[10], 2) + Math.pow(a[11], 2) + Math.pow(a[12], 2) + Math.pow(a[13], 2) + Math.pow(a[14], 2) + Math.pow(a[15], 2) )) +} + +/** + * Adds two mat4's + * + * @param {mat4} out the receiving matrix + * @param {mat4} a the first operand + * @param {mat4} b the second operand + * @returns {mat4} out + */ +export function add(out, a, b) { + out[0] = a[0] + b[0]; + out[1] = a[1] + b[1]; + out[2] = a[2] + b[2]; + out[3] = a[3] + b[3]; + out[4] = a[4] + b[4]; + out[5] = a[5] + b[5]; + out[6] = a[6] + b[6]; + out[7] = a[7] + b[7]; + out[8] = a[8] + b[8]; + out[9] = a[9] + b[9]; + out[10] = a[10] + b[10]; + out[11] = a[11] + b[11]; + out[12] = a[12] + b[12]; + out[13] = a[13] + b[13]; + out[14] = a[14] + b[14]; + out[15] = a[15] + b[15]; + return out; +} + +/** + * Subtracts matrix b from matrix a + * + * @param {mat4} out the receiving matrix + * @param {mat4} a the first operand + * @param {mat4} b the second operand + * @returns {mat4} out + */ +export function subtract(out, a, b) { + out[0] = a[0] - b[0]; + out[1] = a[1] - b[1]; + out[2] = a[2] - b[2]; + out[3] = a[3] - b[3]; + out[4] = a[4] - b[4]; + out[5] = a[5] - b[5]; + out[6] = a[6] - b[6]; + out[7] = a[7] - b[7]; + out[8] = a[8] - b[8]; + out[9] = a[9] - b[9]; + out[10] = a[10] - b[10]; + out[11] = a[11] - b[11]; + out[12] = a[12] - b[12]; + out[13] = a[13] - b[13]; + out[14] = a[14] - b[14]; + out[15] = a[15] - b[15]; + return out; +} + +/** + * Multiply each element of the matrix by a scalar. + * + * @param {mat4} out the receiving matrix + * @param {mat4} a the matrix to scale + * @param {Number} b amount to scale the matrix's elements by + * @returns {mat4} out + */ +export function multiplyScalar(out, a, b) { + out[0] = a[0] * b; + out[1] = a[1] * b; + out[2] = a[2] * b; + out[3] = a[3] * b; + out[4] = a[4] * b; + out[5] = a[5] * b; + out[6] = a[6] * b; + out[7] = a[7] * b; + out[8] = a[8] * b; + out[9] = a[9] * b; + out[10] = a[10] * b; + out[11] = a[11] * b; + out[12] = a[12] * b; + out[13] = a[13] * b; + out[14] = a[14] * b; + out[15] = a[15] * b; + return out; +} + +/** + * Adds two mat4's after multiplying each element of the second operand by a scalar value. + * + * @param {mat4} out the receiving vector + * @param {mat4} a the first operand + * @param {mat4} b the second operand + * @param {Number} scale the amount to scale b's elements by before adding + * @returns {mat4} out + */ +export function multiplyScalarAndAdd(out, a, b, scale) { + out[0] = a[0] + (b[0] * scale); + out[1] = a[1] + (b[1] * scale); + out[2] = a[2] + (b[2] * scale); + out[3] = a[3] + (b[3] * scale); + out[4] = a[4] + (b[4] * scale); + out[5] = a[5] + (b[5] * scale); + out[6] = a[6] + (b[6] * scale); + out[7] = a[7] + (b[7] * scale); + out[8] = a[8] + (b[8] * scale); + out[9] = a[9] + (b[9] * scale); + out[10] = a[10] + (b[10] * scale); + out[11] = a[11] + (b[11] * scale); + out[12] = a[12] + (b[12] * scale); + out[13] = a[13] + (b[13] * scale); + out[14] = a[14] + (b[14] * scale); + out[15] = a[15] + (b[15] * scale); + return out; +} + +/** + * Returns whether or not the matrices have exactly the same elements in the same position (when compared with ===) + * + * @param {mat4} a The first matrix. + * @param {mat4} b The second matrix. + * @returns {Boolean} True if the matrices are equal, false otherwise. + */ +export function exactEquals(a, b) { + return a[0] === b[0] && a[1] === b[1] && a[2] === b[2] && a[3] === b[3] && + a[4] === b[4] && a[5] === b[5] && a[6] === b[6] && a[7] === b[7] && + a[8] === b[8] && a[9] === b[9] && a[10] === b[10] && a[11] === b[11] && + a[12] === b[12] && a[13] === b[13] && a[14] === b[14] && a[15] === b[15]; +} + +/** + * Returns whether or not the matrices have approximately the same elements in the same position. + * + * @param {mat4} a The first matrix. + * @param {mat4} b The second matrix. + * @returns {Boolean} True if the matrices are equal, false otherwise. + */ +export function equals(a, b) { + let a0 = a[0], a1 = a[1], a2 = a[2], a3 = a[3]; + let a4 = a[4], a5 = a[5], a6 = a[6], a7 = a[7]; + let a8 = a[8], a9 = a[9], a10 = a[10], a11 = a[11]; + let a12 = a[12], a13 = a[13], a14 = a[14], a15 = a[15]; + + let b0 = b[0], b1 = b[1], b2 = b[2], b3 = b[3]; + let b4 = b[4], b5 = b[5], b6 = b[6], b7 = b[7]; + let b8 = b[8], b9 = b[9], b10 = b[10], b11 = b[11]; + let b12 = b[12], b13 = b[13], b14 = b[14], b15 = b[15]; + + return (Math.abs(a0 - b0) <= glMatrix.EPSILON*Math.max(1.0, Math.abs(a0), Math.abs(b0)) && + Math.abs(a1 - b1) <= glMatrix.EPSILON*Math.max(1.0, Math.abs(a1), Math.abs(b1)) && + Math.abs(a2 - b2) <= glMatrix.EPSILON*Math.max(1.0, Math.abs(a2), Math.abs(b2)) && + Math.abs(a3 - b3) <= glMatrix.EPSILON*Math.max(1.0, Math.abs(a3), Math.abs(b3)) && + Math.abs(a4 - b4) <= glMatrix.EPSILON*Math.max(1.0, Math.abs(a4), Math.abs(b4)) && + Math.abs(a5 - b5) <= glMatrix.EPSILON*Math.max(1.0, Math.abs(a5), Math.abs(b5)) && + Math.abs(a6 - b6) <= glMatrix.EPSILON*Math.max(1.0, Math.abs(a6), Math.abs(b6)) && + Math.abs(a7 - b7) <= glMatrix.EPSILON*Math.max(1.0, Math.abs(a7), Math.abs(b7)) && + Math.abs(a8 - b8) <= glMatrix.EPSILON*Math.max(1.0, Math.abs(a8), Math.abs(b8)) && + Math.abs(a9 - b9) <= glMatrix.EPSILON*Math.max(1.0, Math.abs(a9), Math.abs(b9)) && + Math.abs(a10 - b10) <= glMatrix.EPSILON*Math.max(1.0, Math.abs(a10), Math.abs(b10)) && + Math.abs(a11 - b11) <= glMatrix.EPSILON*Math.max(1.0, Math.abs(a11), Math.abs(b11)) && + Math.abs(a12 - b12) <= glMatrix.EPSILON*Math.max(1.0, Math.abs(a12), Math.abs(b12)) && + Math.abs(a13 - b13) <= glMatrix.EPSILON*Math.max(1.0, Math.abs(a13), Math.abs(b13)) && + Math.abs(a14 - b14) <= glMatrix.EPSILON*Math.max(1.0, Math.abs(a14), Math.abs(b14)) && + Math.abs(a15 - b15) <= glMatrix.EPSILON*Math.max(1.0, Math.abs(a15), Math.abs(b15))); +} + +/** + * Alias for {@link mat4.multiply} + * @function + */ +export const mul = multiply; + +/** + * Alias for {@link mat4.subtract} + * @function + */ +export const sub = subtract; diff --git a/src/globe/beam/glMatrix/old/common.js b/src/globe/beam/glMatrix/old/common.js new file mode 100755 index 0000000..c6e7bb2 --- /dev/null +++ b/src/globe/beam/glMatrix/old/common.js @@ -0,0 +1,68 @@ +/* Copyright (c) 2013, Brandon Jones, Colin MacKenzie IV. All rights reserved. + +Redistribution and use in source and binary forms, with or without modification, +are permitted provided that the following conditions are met: + + * Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR +ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ + +const _GLMAT_EPSILON = 0.000001; +const _GLMAT_RANDOM = Math.random; +var _GLMAT_ARRAY_TYPE = (typeof Float32Array !== 'undefined') ? Float32Array : Array; + +/** + * @class Common utilities + * @name glMatrix + */ +const _glMatrix = {}; + +/** + * Sets the type of array used when creating new vectors and matricies + * + * @param {Type} type Array type, such as Float32Array or Array + */ +_glMatrix.setMatrixArrayType = function(type) { + _GLMAT_ARRAY_TYPE = type; +} + + +var degree = Math.PI / 180; + +/** +* Convert Degree To Radian +* +* @param {Number} Angle in Degrees +*/ +_glMatrix.toRadian = function(a){ + return a * degree; +} + +export var GLMAT_ARRAY_TYPE = _GLMAT_ARRAY_TYPE; +export var GLMAT_EPSILON = _GLMAT_EPSILON; +export var GLMAT_RANDOM = _GLMAT_RANDOM; +export var glMatrix = _glMatrix; + +// if(typeof(exports) !== 'undefined') { +// exports.GLMAT_ARRAY_TYPE = GLMAT_ARRAY_TYPE; +// exports.GLMAT_EPSILON = GLMAT_EPSILON; +// exports.GLMAT_RANDOM = GLMAT_RANDOM; +// exports.glMatrix = glMatrix; +// } + + + + diff --git a/src/globe/beam/glMatrix/old/mat2.js b/src/globe/beam/glMatrix/old/mat2.js new file mode 100755 index 0000000..f1b5216 --- /dev/null +++ b/src/globe/beam/glMatrix/old/mat2.js @@ -0,0 +1,237 @@ +import {GLMAT_ARRAY_TYPE} from "./common"; + +/* Copyright (c) 2013, Brandon Jones, Colin MacKenzie IV. All rights reserved. + +Redistribution and use in source and binary forms, with or without modification, +are permitted provided that the following conditions are met: + + * Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR +ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ + +/** + * @class 2x2 Matrix + * @name mat2 + */ +var mat2 = {}; + +/** + * Creates a new identity mat2 + * + * @returns {mat2} a new 2x2 matrix + */ +mat2.create = function() { + var out = new GLMAT_ARRAY_TYPE(4); + out[0] = 1; + out[1] = 0; + out[2] = 0; + out[3] = 1; + return out; +}; + +/** + * Creates a new mat2 initialized with values from an existing matrix + * + * @param {mat2} a matrix to clone + * @returns {mat2} a new 2x2 matrix + */ +mat2.clone = function(a) { + var out = new GLMAT_ARRAY_TYPE(4); + out[0] = a[0]; + out[1] = a[1]; + out[2] = a[2]; + out[3] = a[3]; + return out; +}; + +/** + * Copy the values from one mat2 to another + * + * @param {mat2} out the receiving matrix + * @param {mat2} a the source matrix + * @returns {mat2} out + */ +mat2.copy = function(out, a) { + out[0] = a[0]; + out[1] = a[1]; + out[2] = a[2]; + out[3] = a[3]; + return out; +}; + +/** + * Set a mat2 to the identity matrix + * + * @param {mat2} out the receiving matrix + * @returns {mat2} out + */ +mat2.identity = function(out) { + out[0] = 1; + out[1] = 0; + out[2] = 0; + out[3] = 1; + return out; +}; + +/** + * Transpose the values of a mat2 + * + * @param {mat2} out the receiving matrix + * @param {mat2} a the source matrix + * @returns {mat2} out + */ +mat2.transpose = function(out, a) { + // If we are transposing ourselves we can skip a few steps but have to cache some values + if (out === a) { + var a1 = a[1]; + out[1] = a[2]; + out[2] = a1; + } else { + out[0] = a[0]; + out[1] = a[2]; + out[2] = a[1]; + out[3] = a[3]; + } + + return out; +}; + +/** + * Inverts a mat2 + * + * @param {mat2} out the receiving matrix + * @param {mat2} a the source matrix + * @returns {mat2} out + */ +mat2.invert = function(out, a) { + var a0 = a[0], a1 = a[1], a2 = a[2], a3 = a[3], + + // Calculate the determinant + det = a0 * a3 - a2 * a1; + + if (!det) { + return null; + } + det = 1.0 / det; + + out[0] = a3 * det; + out[1] = -a1 * det; + out[2] = -a2 * det; + out[3] = a0 * det; + + return out; +}; + +/** + * Calculates the adjugate of a mat2 + * + * @param {mat2} out the receiving matrix + * @param {mat2} a the source matrix + * @returns {mat2} out + */ +mat2.adjoint = function(out, a) { + // Caching this value is nessecary if out == a + var a0 = a[0]; + out[0] = a[3]; + out[1] = -a[1]; + out[2] = -a[2]; + out[3] = a0; + + return out; +}; + +/** + * Calculates the determinant of a mat2 + * + * @param {mat2} a the source matrix + * @returns {Number} determinant of a + */ +mat2.determinant = function (a) { + return a[0] * a[3] - a[2] * a[1]; +}; + +/** + * Multiplies two mat2's + * + * @param {mat2} out the receiving matrix + * @param {mat2} a the first operand + * @param {mat2} b the second operand + * @returns {mat2} out + */ +mat2.multiply = function (out, a, b) { + var a0 = a[0], a1 = a[1], a2 = a[2], a3 = a[3]; + var b0 = b[0], b1 = b[1], b2 = b[2], b3 = b[3]; + out[0] = a0 * b0 + a1 * b2; + out[1] = a0 * b1 + a1 * b3; + out[2] = a2 * b0 + a3 * b2; + out[3] = a2 * b1 + a3 * b3; + return out; +}; + +/** + * Alias for {@link mat2.multiply} + * @function + */ +mat2.mul = mat2.multiply; + +/** + * Rotates a mat2 by the given angle + * + * @param {mat2} out the receiving matrix + * @param {mat2} a the matrix to rotate + * @param {Number} rad the angle to rotate the matrix by + * @returns {mat2} out + */ +mat2.rotate = function (out, a, rad) { + var a0 = a[0], a1 = a[1], a2 = a[2], a3 = a[3], + s = Math.sin(rad), + c = Math.cos(rad); + out[0] = a0 * c + a1 * s; + out[1] = a0 * -s + a1 * c; + out[2] = a2 * c + a3 * s; + out[3] = a2 * -s + a3 * c; + return out; +}; + +/** + * Scales the mat2 by the dimensions in the given vec2 + * + * @param {mat2} out the receiving matrix + * @param {mat2} a the matrix to rotate + * @param {vec2} v the vec2 to scale the matrix by + * @returns {mat2} out + **/ +mat2.scale = function(out, a, v) { + var a0 = a[0], a1 = a[1], a2 = a[2], a3 = a[3], + v0 = v[0], v1 = v[1]; + out[0] = a0 * v0; + out[1] = a1 * v1; + out[2] = a2 * v0; + out[3] = a3 * v1; + return out; +}; + +/** + * Returns a string representation of a mat2 + * + * @param {mat2} mat matrix to represent as a string + * @returns {String} string representation of the matrix + */ +mat2.str = function (a) { + return 'mat2(' + a[0] + ', ' + a[1] + ', ' + a[2] + ', ' + a[3] + ')'; +}; + +export default mat2; \ No newline at end of file diff --git a/src/globe/beam/glMatrix/old/mat2d.js b/src/globe/beam/glMatrix/old/mat2d.js new file mode 100755 index 0000000..cd92775 --- /dev/null +++ b/src/globe/beam/glMatrix/old/mat2d.js @@ -0,0 +1,253 @@ +import {GLMAT_ARRAY_TYPE} from "./common"; + +/* Copyright (c) 2013, Brandon Jones, Colin MacKenzie IV. All rights reserved. + +Redistribution and use in source and binary forms, with or without modification, +are permitted provided that the following conditions are met: + + * Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR +ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ + +/** + * @class 2x3 Matrix + * @name mat2d + * + * @description + * A mat2d contains six elements defined as: + *
+ * [a, b,
+ *  c, d,
+ *  tx,ty]
+ * 
+ * This is a short form for the 3x3 matrix: + *
+ * [a, b, 0
+ *  c, d, 0
+ *  tx,ty,1]
+ * 
+ * The last column is ignored so the array is shorter and operations are faster. + */ +var mat2d = {}; + +/** + * Creates a new identity mat2d + * + * @returns {mat2d} a new 2x3 matrix + */ +mat2d.create = function() { + var out = new GLMAT_ARRAY_TYPE(6); + out[0] = 1; + out[1] = 0; + out[2] = 0; + out[3] = 1; + out[4] = 0; + out[5] = 0; + return out; +}; + +/** + * Creates a new mat2d initialized with values from an existing matrix + * + * @param {mat2d} a matrix to clone + * @returns {mat2d} a new 2x3 matrix + */ +mat2d.clone = function(a) { + var out = new GLMAT_ARRAY_TYPE(6); + out[0] = a[0]; + out[1] = a[1]; + out[2] = a[2]; + out[3] = a[3]; + out[4] = a[4]; + out[5] = a[5]; + return out; +}; + +/** + * Copy the values from one mat2d to another + * + * @param {mat2d} out the receiving matrix + * @param {mat2d} a the source matrix + * @returns {mat2d} out + */ +mat2d.copy = function(out, a) { + out[0] = a[0]; + out[1] = a[1]; + out[2] = a[2]; + out[3] = a[3]; + out[4] = a[4]; + out[5] = a[5]; + return out; +}; + +/** + * Set a mat2d to the identity matrix + * + * @param {mat2d} out the receiving matrix + * @returns {mat2d} out + */ +mat2d.identity = function(out) { + out[0] = 1; + out[1] = 0; + out[2] = 0; + out[3] = 1; + out[4] = 0; + out[5] = 0; + return out; +}; + +/** + * Inverts a mat2d + * + * @param {mat2d} out the receiving matrix + * @param {mat2d} a the source matrix + * @returns {mat2d} out + */ +mat2d.invert = function(out, a) { + var aa = a[0], ab = a[1], ac = a[2], ad = a[3], + atx = a[4], aty = a[5]; + + var det = aa * ad - ab * ac; + if(!det){ + return null; + } + det = 1.0 / det; + + out[0] = ad * det; + out[1] = -ab * det; + out[2] = -ac * det; + out[3] = aa * det; + out[4] = (ac * aty - ad * atx) * det; + out[5] = (ab * atx - aa * aty) * det; + return out; +}; + +/** + * Calculates the determinant of a mat2d + * + * @param {mat2d} a the source matrix + * @returns {Number} determinant of a + */ +mat2d.determinant = function (a) { + return a[0] * a[3] - a[1] * a[2]; +}; + +/** + * Multiplies two mat2d's + * + * @param {mat2d} out the receiving matrix + * @param {mat2d} a the first operand + * @param {mat2d} b the second operand + * @returns {mat2d} out + */ +mat2d.multiply = function (out, a, b) { + var aa = a[0], ab = a[1], ac = a[2], ad = a[3], + atx = a[4], aty = a[5], + ba = b[0], bb = b[1], bc = b[2], bd = b[3], + btx = b[4], bty = b[5]; + + out[0] = aa*ba + ab*bc; + out[1] = aa*bb + ab*bd; + out[2] = ac*ba + ad*bc; + out[3] = ac*bb + ad*bd; + out[4] = ba*atx + bc*aty + btx; + out[5] = bb*atx + bd*aty + bty; + return out; +}; + +/** + * Alias for {@link mat2d.multiply} + * @function + */ +mat2d.mul = mat2d.multiply; + + +/** + * Rotates a mat2d by the given angle + * + * @param {mat2d} out the receiving matrix + * @param {mat2d} a the matrix to rotate + * @param {Number} rad the angle to rotate the matrix by + * @returns {mat2d} out + */ +mat2d.rotate = function (out, a, rad) { + var aa = a[0], + ab = a[1], + ac = a[2], + ad = a[3], + atx = a[4], + aty = a[5], + st = Math.sin(rad), + ct = Math.cos(rad); + + out[0] = aa*ct + ab*st; + out[1] = -aa*st + ab*ct; + out[2] = ac*ct + ad*st; + out[3] = -ac*st + ct*ad; + out[4] = ct*atx + st*aty; + out[5] = ct*aty - st*atx; + return out; +}; + +/** + * Scales the mat2d by the dimensions in the given vec2 + * + * @param {mat2d} out the receiving matrix + * @param {mat2d} a the matrix to translate + * @param {vec2} v the vec2 to scale the matrix by + * @returns {mat2d} out + **/ +mat2d.scale = function(out, a, v) { + var vx = v[0], vy = v[1]; + out[0] = a[0] * vx; + out[1] = a[1] * vy; + out[2] = a[2] * vx; + out[3] = a[3] * vy; + out[4] = a[4] * vx; + out[5] = a[5] * vy; + return out; +}; + +/** + * Translates the mat2d by the dimensions in the given vec2 + * + * @param {mat2d} out the receiving matrix + * @param {mat2d} a the matrix to translate + * @param {vec2} v the vec2 to translate the matrix by + * @returns {mat2d} out + **/ +mat2d.translate = function(out, a, v) { + out[0] = a[0]; + out[1] = a[1]; + out[2] = a[2]; + out[3] = a[3]; + out[4] = a[4] + v[0]; + out[5] = a[5] + v[1]; + return out; +}; + +/** + * Returns a string representation of a mat2d + * + * @param {mat2d} a matrix to represent as a string + * @returns {String} string representation of the matrix + */ +mat2d.str = function (a) { + return 'mat2d(' + a[0] + ', ' + a[1] + ', ' + a[2] + ', ' + + a[3] + ', ' + a[4] + ', ' + a[5] + ')'; +}; + +export default mat2d; diff --git a/src/globe/beam/glMatrix/old/mat3.js b/src/globe/beam/glMatrix/old/mat3.js new file mode 100755 index 0000000..bcc7b02 --- /dev/null +++ b/src/globe/beam/glMatrix/old/mat3.js @@ -0,0 +1,478 @@ +import {GLMAT_ARRAY_TYPE} from "./common"; + +/* Copyright (c) 2013, Brandon Jones, Colin MacKenzie IV. All rights reserved. + +Redistribution and use in source and binary forms, with or without modification, +are permitted provided that the following conditions are met: + + * Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR +ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ + +/** + * @class 3x3 Matrix + * @name mat3 + */ +var mat3 = {}; + +/** + * Creates a new identity mat3 + * + * @returns {mat3} a new 3x3 matrix + */ +mat3.create = function() { + var out = new GLMAT_ARRAY_TYPE(9); + out[0] = 1; + out[1] = 0; + out[2] = 0; + out[3] = 0; + out[4] = 1; + out[5] = 0; + out[6] = 0; + out[7] = 0; + out[8] = 1; + return out; +}; + +/** + * Copies the upper-left 3x3 values into the given mat3. + * + * @param {mat3} out the receiving 3x3 matrix + * @param {mat4} a the source 4x4 matrix + * @returns {mat3} out + */ +mat3.fromMat4 = function(out, a) { + out[0] = a[0]; + out[1] = a[1]; + out[2] = a[2]; + out[3] = a[4]; + out[4] = a[5]; + out[5] = a[6]; + out[6] = a[8]; + out[7] = a[9]; + out[8] = a[10]; + return out; +}; + +/** + * Creates a new mat3 initialized with values from an existing matrix + * + * @param {mat3} a matrix to clone + * @returns {mat3} a new 3x3 matrix + */ +mat3.clone = function(a) { + var out = new GLMAT_ARRAY_TYPE(9); + out[0] = a[0]; + out[1] = a[1]; + out[2] = a[2]; + out[3] = a[3]; + out[4] = a[4]; + out[5] = a[5]; + out[6] = a[6]; + out[7] = a[7]; + out[8] = a[8]; + return out; +}; + +/** + * Copy the values from one mat3 to another + * + * @param {mat3} out the receiving matrix + * @param {mat3} a the source matrix + * @returns {mat3} out + */ +mat3.copy = function(out, a) { + out[0] = a[0]; + out[1] = a[1]; + out[2] = a[2]; + out[3] = a[3]; + out[4] = a[4]; + out[5] = a[5]; + out[6] = a[6]; + out[7] = a[7]; + out[8] = a[8]; + return out; +}; + +/** + * Set a mat3 to the identity matrix + * + * @param {mat3} out the receiving matrix + * @returns {mat3} out + */ +mat3.identity = function(out) { + out[0] = 1; + out[1] = 0; + out[2] = 0; + out[3] = 0; + out[4] = 1; + out[5] = 0; + out[6] = 0; + out[7] = 0; + out[8] = 1; + return out; +}; + +/** + * Transpose the values of a mat3 + * + * @param {mat3} out the receiving matrix + * @param {mat3} a the source matrix + * @returns {mat3} out + */ +mat3.transpose = function(out, a) { + // If we are transposing ourselves we can skip a few steps but have to cache some values + if (out === a) { + var a01 = a[1], a02 = a[2], a12 = a[5]; + out[1] = a[3]; + out[2] = a[6]; + out[3] = a01; + out[5] = a[7]; + out[6] = a02; + out[7] = a12; + } else { + out[0] = a[0]; + out[1] = a[3]; + out[2] = a[6]; + out[3] = a[1]; + out[4] = a[4]; + out[5] = a[7]; + out[6] = a[2]; + out[7] = a[5]; + out[8] = a[8]; + } + + return out; +}; + +/** + * Inverts a mat3 + * + * @param {mat3} out the receiving matrix + * @param {mat3} a the source matrix + * @returns {mat3} out + */ +mat3.invert = function(out, a) { + var a00 = a[0], a01 = a[1], a02 = a[2], + a10 = a[3], a11 = a[4], a12 = a[5], + a20 = a[6], a21 = a[7], a22 = a[8], + + b01 = a22 * a11 - a12 * a21, + b11 = -a22 * a10 + a12 * a20, + b21 = a21 * a10 - a11 * a20, + + // Calculate the determinant + det = a00 * b01 + a01 * b11 + a02 * b21; + + if (!det) { + return null; + } + det = 1.0 / det; + + out[0] = b01 * det; + out[1] = (-a22 * a01 + a02 * a21) * det; + out[2] = (a12 * a01 - a02 * a11) * det; + out[3] = b11 * det; + out[4] = (a22 * a00 - a02 * a20) * det; + out[5] = (-a12 * a00 + a02 * a10) * det; + out[6] = b21 * det; + out[7] = (-a21 * a00 + a01 * a20) * det; + out[8] = (a11 * a00 - a01 * a10) * det; + return out; +}; + +/** + * Calculates the adjugate of a mat3 + * + * @param {mat3} out the receiving matrix + * @param {mat3} a the source matrix + * @returns {mat3} out + */ +mat3.adjoint = function(out, a) { + var a00 = a[0], a01 = a[1], a02 = a[2], + a10 = a[3], a11 = a[4], a12 = a[5], + a20 = a[6], a21 = a[7], a22 = a[8]; + + out[0] = (a11 * a22 - a12 * a21); + out[1] = (a02 * a21 - a01 * a22); + out[2] = (a01 * a12 - a02 * a11); + out[3] = (a12 * a20 - a10 * a22); + out[4] = (a00 * a22 - a02 * a20); + out[5] = (a02 * a10 - a00 * a12); + out[6] = (a10 * a21 - a11 * a20); + out[7] = (a01 * a20 - a00 * a21); + out[8] = (a00 * a11 - a01 * a10); + return out; +}; + +/** + * Calculates the determinant of a mat3 + * + * @param {mat3} a the source matrix + * @returns {Number} determinant of a + */ +mat3.determinant = function (a) { + var a00 = a[0], a01 = a[1], a02 = a[2], + a10 = a[3], a11 = a[4], a12 = a[5], + a20 = a[6], a21 = a[7], a22 = a[8]; + + return a00 * (a22 * a11 - a12 * a21) + a01 * (-a22 * a10 + a12 * a20) + a02 * (a21 * a10 - a11 * a20); +}; + +/** + * Multiplies two mat3's + * + * @param {mat3} out the receiving matrix + * @param {mat3} a the first operand + * @param {mat3} b the second operand + * @returns {mat3} out + */ +mat3.multiply = function (out, a, b) { + var a00 = a[0], a01 = a[1], a02 = a[2], + a10 = a[3], a11 = a[4], a12 = a[5], + a20 = a[6], a21 = a[7], a22 = a[8], + + b00 = b[0], b01 = b[1], b02 = b[2], + b10 = b[3], b11 = b[4], b12 = b[5], + b20 = b[6], b21 = b[7], b22 = b[8]; + + out[0] = b00 * a00 + b01 * a10 + b02 * a20; + out[1] = b00 * a01 + b01 * a11 + b02 * a21; + out[2] = b00 * a02 + b01 * a12 + b02 * a22; + + out[3] = b10 * a00 + b11 * a10 + b12 * a20; + out[4] = b10 * a01 + b11 * a11 + b12 * a21; + out[5] = b10 * a02 + b11 * a12 + b12 * a22; + + out[6] = b20 * a00 + b21 * a10 + b22 * a20; + out[7] = b20 * a01 + b21 * a11 + b22 * a21; + out[8] = b20 * a02 + b21 * a12 + b22 * a22; + return out; +}; + +/** + * Alias for {@link mat3.multiply} + * @function + */ +mat3.mul = mat3.multiply; + +/** + * Translate a mat3 by the given vector + * + * @param {mat3} out the receiving matrix + * @param {mat3} a the matrix to translate + * @param {vec2} v vector to translate by + * @returns {mat3} out + */ +mat3.translate = function(out, a, v) { + var a00 = a[0], a01 = a[1], a02 = a[2], + a10 = a[3], a11 = a[4], a12 = a[5], + a20 = a[6], a21 = a[7], a22 = a[8], + x = v[0], y = v[1]; + + out[0] = a00; + out[1] = a01; + out[2] = a02; + + out[3] = a10; + out[4] = a11; + out[5] = a12; + + out[6] = x * a00 + y * a10 + a20; + out[7] = x * a01 + y * a11 + a21; + out[8] = x * a02 + y * a12 + a22; + return out; +}; + +/** + * Rotates a mat3 by the given angle + * + * @param {mat3} out the receiving matrix + * @param {mat3} a the matrix to rotate + * @param {Number} rad the angle to rotate the matrix by + * @returns {mat3} out + */ +mat3.rotate = function (out, a, rad) { + var a00 = a[0], a01 = a[1], a02 = a[2], + a10 = a[3], a11 = a[4], a12 = a[5], + a20 = a[6], a21 = a[7], a22 = a[8], + + s = Math.sin(rad), + c = Math.cos(rad); + + out[0] = c * a00 + s * a10; + out[1] = c * a01 + s * a11; + out[2] = c * a02 + s * a12; + + out[3] = c * a10 - s * a00; + out[4] = c * a11 - s * a01; + out[5] = c * a12 - s * a02; + + out[6] = a20; + out[7] = a21; + out[8] = a22; + return out; +}; + +/** + * Scales the mat3 by the dimensions in the given vec2 + * + * @param {mat3} out the receiving matrix + * @param {mat3} a the matrix to rotate + * @param {vec2} v the vec2 to scale the matrix by + * @returns {mat3} out + **/ +mat3.scale = function(out, a, v) { + var x = v[0], y = v[1]; + + out[0] = x * a[0]; + out[1] = x * a[1]; + out[2] = x * a[2]; + + out[3] = y * a[3]; + out[4] = y * a[4]; + out[5] = y * a[5]; + + out[6] = a[6]; + out[7] = a[7]; + out[8] = a[8]; + return out; +}; + +/** + * Copies the values from a mat2d into a mat3 + * + * @param {mat3} out the receiving matrix + * @param {mat2d} a the matrix to copy + * @returns {mat3} out + **/ +mat3.fromMat2d = function(out, a) { + out[0] = a[0]; + out[1] = a[1]; + out[2] = 0; + + out[3] = a[2]; + out[4] = a[3]; + out[5] = 0; + + out[6] = a[4]; + out[7] = a[5]; + out[8] = 1; + return out; +}; + +/** +* Calculates a 3x3 matrix from the given quaternion +* +* @param {mat3} out mat3 receiving operation result +* @param {quat} q Quaternion to create matrix from +* +* @returns {mat3} out +*/ +mat3.fromQuat = function (out, q) { + var x = q[0], y = q[1], z = q[2], w = q[3], + x2 = x + x, + y2 = y + y, + z2 = z + z, + + xx = x * x2, + xy = x * y2, + xz = x * z2, + yy = y * y2, + yz = y * z2, + zz = z * z2, + wx = w * x2, + wy = w * y2, + wz = w * z2; + + out[0] = 1 - (yy + zz); + out[3] = xy + wz; + out[6] = xz - wy; + + out[1] = xy - wz; + out[4] = 1 - (xx + zz); + out[7] = yz + wx; + + out[2] = xz + wy; + out[5] = yz - wx; + out[8] = 1 - (xx + yy); + + return out; +}; + +/** +* Calculates a 3x3 normal matrix (transpose inverse) from the 4x4 matrix +* +* @param {mat3} out mat3 receiving operation result +* @param {mat4} a Mat4 to derive the normal matrix from +* +* @returns {mat3} out +*/ +mat3.normalFromMat4 = function (out, a) { + var a00 = a[0], a01 = a[1], a02 = a[2], a03 = a[3], + a10 = a[4], a11 = a[5], a12 = a[6], a13 = a[7], + a20 = a[8], a21 = a[9], a22 = a[10], a23 = a[11], + a30 = a[12], a31 = a[13], a32 = a[14], a33 = a[15], + + b00 = a00 * a11 - a01 * a10, + b01 = a00 * a12 - a02 * a10, + b02 = a00 * a13 - a03 * a10, + b03 = a01 * a12 - a02 * a11, + b04 = a01 * a13 - a03 * a11, + b05 = a02 * a13 - a03 * a12, + b06 = a20 * a31 - a21 * a30, + b07 = a20 * a32 - a22 * a30, + b08 = a20 * a33 - a23 * a30, + b09 = a21 * a32 - a22 * a31, + b10 = a21 * a33 - a23 * a31, + b11 = a22 * a33 - a23 * a32, + + // Calculate the determinant + det = b00 * b11 - b01 * b10 + b02 * b09 + b03 * b08 - b04 * b07 + b05 * b06; + + if (!det) { + return null; + } + det = 1.0 / det; + + out[0] = (a11 * b11 - a12 * b10 + a13 * b09) * det; + out[1] = (a12 * b08 - a10 * b11 - a13 * b07) * det; + out[2] = (a10 * b10 - a11 * b08 + a13 * b06) * det; + + out[3] = (a02 * b10 - a01 * b11 - a03 * b09) * det; + out[4] = (a00 * b11 - a02 * b08 + a03 * b07) * det; + out[5] = (a01 * b08 - a00 * b10 - a03 * b06) * det; + + out[6] = (a31 * b05 - a32 * b04 + a33 * b03) * det; + out[7] = (a32 * b02 - a30 * b05 - a33 * b01) * det; + out[8] = (a30 * b04 - a31 * b02 + a33 * b00) * det; + + return out; +}; + +/** + * Returns a string representation of a mat3 + * + * @param {mat3} mat matrix to represent as a string + * @returns {String} string representation of the matrix + */ +mat3.str = function (a) { + return 'mat3(' + a[0] + ', ' + a[1] + ', ' + a[2] + ', ' + + a[3] + ', ' + a[4] + ', ' + a[5] + ', ' + + a[6] + ', ' + a[7] + ', ' + a[8] + ')'; +}; + +export default mat3; diff --git a/src/globe/beam/glMatrix/old/mat4.js b/src/globe/beam/glMatrix/old/mat4.js new file mode 100755 index 0000000..98bd03d --- /dev/null +++ b/src/globe/beam/glMatrix/old/mat4.js @@ -0,0 +1,908 @@ +import {GLMAT_ARRAY_TYPE} from "./common"; +import {GLMAT_EPSILON} from "./common"; + +/* Copyright (c) 2013, Brandon Jones, Colin MacKenzie IV. All rights reserved. + +Redistribution and use in source and binary forms, with or without modification, +are permitted provided that the following conditions are met: + + * Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR +ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ + +/** + * @class 4x4 Matrix + * @name mat4 + */ +var mat4 = {}; + +/** + * Creates a new identity mat4 + * + * @returns {mat4} a new 4x4 matrix + */ +mat4.create = function() { + var out = new GLMAT_ARRAY_TYPE(16); + out[0] = 1; + out[1] = 0; + out[2] = 0; + out[3] = 0; + out[4] = 0; + out[5] = 1; + out[6] = 0; + out[7] = 0; + out[8] = 0; + out[9] = 0; + out[10] = 1; + out[11] = 0; + out[12] = 0; + out[13] = 0; + out[14] = 0; + out[15] = 1; + return out; +}; + +/** + * Creates a new mat4 initialized with values from an existing matrix + * + * @param {mat4} a matrix to clone + * @returns {mat4} a new 4x4 matrix + */ +mat4.clone = function(a) { + var out = new GLMAT_ARRAY_TYPE(16); + out[0] = a[0]; + out[1] = a[1]; + out[2] = a[2]; + out[3] = a[3]; + out[4] = a[4]; + out[5] = a[5]; + out[6] = a[6]; + out[7] = a[7]; + out[8] = a[8]; + out[9] = a[9]; + out[10] = a[10]; + out[11] = a[11]; + out[12] = a[12]; + out[13] = a[13]; + out[14] = a[14]; + out[15] = a[15]; + return out; +}; + +/** + * Copy the values from one mat4 to another + * + * @param {mat4} out the receiving matrix + * @param {mat4} a the source matrix + * @returns {mat4} out + */ +mat4.copy = function(out, a) { + out[0] = a[0]; + out[1] = a[1]; + out[2] = a[2]; + out[3] = a[3]; + out[4] = a[4]; + out[5] = a[5]; + out[6] = a[6]; + out[7] = a[7]; + out[8] = a[8]; + out[9] = a[9]; + out[10] = a[10]; + out[11] = a[11]; + out[12] = a[12]; + out[13] = a[13]; + out[14] = a[14]; + out[15] = a[15]; + return out; +}; + +/** + * Set a mat4 to the identity matrix + * + * @param {mat4} out the receiving matrix + * @returns {mat4} out + */ +mat4.identity = function(out) { + out[0] = 1; + out[1] = 0; + out[2] = 0; + out[3] = 0; + out[4] = 0; + out[5] = 1; + out[6] = 0; + out[7] = 0; + out[8] = 0; + out[9] = 0; + out[10] = 1; + out[11] = 0; + out[12] = 0; + out[13] = 0; + out[14] = 0; + out[15] = 1; + return out; +}; + +/** + * Transpose the values of a mat4 + * + * @param {mat4} out the receiving matrix + * @param {mat4} a the source matrix + * @returns {mat4} out + */ +mat4.transpose = function(out, a) { + // If we are transposing ourselves we can skip a few steps but have to cache some values + if (out === a) { + var a01 = a[1], a02 = a[2], a03 = a[3], + a12 = a[6], a13 = a[7], + a23 = a[11]; + + out[1] = a[4]; + out[2] = a[8]; + out[3] = a[12]; + out[4] = a01; + out[6] = a[9]; + out[7] = a[13]; + out[8] = a02; + out[9] = a12; + out[11] = a[14]; + out[12] = a03; + out[13] = a13; + out[14] = a23; + } else { + out[0] = a[0]; + out[1] = a[4]; + out[2] = a[8]; + out[3] = a[12]; + out[4] = a[1]; + out[5] = a[5]; + out[6] = a[9]; + out[7] = a[13]; + out[8] = a[2]; + out[9] = a[6]; + out[10] = a[10]; + out[11] = a[14]; + out[12] = a[3]; + out[13] = a[7]; + out[14] = a[11]; + out[15] = a[15]; + } + + return out; +}; + +/** + * Inverts a mat4 + * + * @param {mat4} out the receiving matrix + * @param {mat4} a the source matrix + * @returns {mat4} out + */ +mat4.invert = function(out, a) { + var a00 = a[0], a01 = a[1], a02 = a[2], a03 = a[3], + a10 = a[4], a11 = a[5], a12 = a[6], a13 = a[7], + a20 = a[8], a21 = a[9], a22 = a[10], a23 = a[11], + a30 = a[12], a31 = a[13], a32 = a[14], a33 = a[15], + + b00 = a00 * a11 - a01 * a10, + b01 = a00 * a12 - a02 * a10, + b02 = a00 * a13 - a03 * a10, + b03 = a01 * a12 - a02 * a11, + b04 = a01 * a13 - a03 * a11, + b05 = a02 * a13 - a03 * a12, + b06 = a20 * a31 - a21 * a30, + b07 = a20 * a32 - a22 * a30, + b08 = a20 * a33 - a23 * a30, + b09 = a21 * a32 - a22 * a31, + b10 = a21 * a33 - a23 * a31, + b11 = a22 * a33 - a23 * a32, + + // Calculate the determinant + det = b00 * b11 - b01 * b10 + b02 * b09 + b03 * b08 - b04 * b07 + b05 * b06; + + if (!det) { + return null; + } + det = 1.0 / det; + + out[0] = (a11 * b11 - a12 * b10 + a13 * b09) * det; + out[1] = (a02 * b10 - a01 * b11 - a03 * b09) * det; + out[2] = (a31 * b05 - a32 * b04 + a33 * b03) * det; + out[3] = (a22 * b04 - a21 * b05 - a23 * b03) * det; + out[4] = (a12 * b08 - a10 * b11 - a13 * b07) * det; + out[5] = (a00 * b11 - a02 * b08 + a03 * b07) * det; + out[6] = (a32 * b02 - a30 * b05 - a33 * b01) * det; + out[7] = (a20 * b05 - a22 * b02 + a23 * b01) * det; + out[8] = (a10 * b10 - a11 * b08 + a13 * b06) * det; + out[9] = (a01 * b08 - a00 * b10 - a03 * b06) * det; + out[10] = (a30 * b04 - a31 * b02 + a33 * b00) * det; + out[11] = (a21 * b02 - a20 * b04 - a23 * b00) * det; + out[12] = (a11 * b07 - a10 * b09 - a12 * b06) * det; + out[13] = (a00 * b09 - a01 * b07 + a02 * b06) * det; + out[14] = (a31 * b01 - a30 * b03 - a32 * b00) * det; + out[15] = (a20 * b03 - a21 * b01 + a22 * b00) * det; + + return out; +}; + +/** + * Calculates the adjugate of a mat4 + * + * @param {mat4} out the receiving matrix + * @param {mat4} a the source matrix + * @returns {mat4} out + */ +mat4.adjoint = function(out, a) { + var a00 = a[0], a01 = a[1], a02 = a[2], a03 = a[3], + a10 = a[4], a11 = a[5], a12 = a[6], a13 = a[7], + a20 = a[8], a21 = a[9], a22 = a[10], a23 = a[11], + a30 = a[12], a31 = a[13], a32 = a[14], a33 = a[15]; + + out[0] = (a11 * (a22 * a33 - a23 * a32) - a21 * (a12 * a33 - a13 * a32) + a31 * (a12 * a23 - a13 * a22)); + out[1] = -(a01 * (a22 * a33 - a23 * a32) - a21 * (a02 * a33 - a03 * a32) + a31 * (a02 * a23 - a03 * a22)); + out[2] = (a01 * (a12 * a33 - a13 * a32) - a11 * (a02 * a33 - a03 * a32) + a31 * (a02 * a13 - a03 * a12)); + out[3] = -(a01 * (a12 * a23 - a13 * a22) - a11 * (a02 * a23 - a03 * a22) + a21 * (a02 * a13 - a03 * a12)); + out[4] = -(a10 * (a22 * a33 - a23 * a32) - a20 * (a12 * a33 - a13 * a32) + a30 * (a12 * a23 - a13 * a22)); + out[5] = (a00 * (a22 * a33 - a23 * a32) - a20 * (a02 * a33 - a03 * a32) + a30 * (a02 * a23 - a03 * a22)); + out[6] = -(a00 * (a12 * a33 - a13 * a32) - a10 * (a02 * a33 - a03 * a32) + a30 * (a02 * a13 - a03 * a12)); + out[7] = (a00 * (a12 * a23 - a13 * a22) - a10 * (a02 * a23 - a03 * a22) + a20 * (a02 * a13 - a03 * a12)); + out[8] = (a10 * (a21 * a33 - a23 * a31) - a20 * (a11 * a33 - a13 * a31) + a30 * (a11 * a23 - a13 * a21)); + out[9] = -(a00 * (a21 * a33 - a23 * a31) - a20 * (a01 * a33 - a03 * a31) + a30 * (a01 * a23 - a03 * a21)); + out[10] = (a00 * (a11 * a33 - a13 * a31) - a10 * (a01 * a33 - a03 * a31) + a30 * (a01 * a13 - a03 * a11)); + out[11] = -(a00 * (a11 * a23 - a13 * a21) - a10 * (a01 * a23 - a03 * a21) + a20 * (a01 * a13 - a03 * a11)); + out[12] = -(a10 * (a21 * a32 - a22 * a31) - a20 * (a11 * a32 - a12 * a31) + a30 * (a11 * a22 - a12 * a21)); + out[13] = (a00 * (a21 * a32 - a22 * a31) - a20 * (a01 * a32 - a02 * a31) + a30 * (a01 * a22 - a02 * a21)); + out[14] = -(a00 * (a11 * a32 - a12 * a31) - a10 * (a01 * a32 - a02 * a31) + a30 * (a01 * a12 - a02 * a11)); + out[15] = (a00 * (a11 * a22 - a12 * a21) - a10 * (a01 * a22 - a02 * a21) + a20 * (a01 * a12 - a02 * a11)); + return out; +}; + +/** + * Calculates the determinant of a mat4 + * + * @param {mat4} a the source matrix + * @returns {Number} determinant of a + */ +mat4.determinant = function (a) { + var a00 = a[0], a01 = a[1], a02 = a[2], a03 = a[3], + a10 = a[4], a11 = a[5], a12 = a[6], a13 = a[7], + a20 = a[8], a21 = a[9], a22 = a[10], a23 = a[11], + a30 = a[12], a31 = a[13], a32 = a[14], a33 = a[15], + + b00 = a00 * a11 - a01 * a10, + b01 = a00 * a12 - a02 * a10, + b02 = a00 * a13 - a03 * a10, + b03 = a01 * a12 - a02 * a11, + b04 = a01 * a13 - a03 * a11, + b05 = a02 * a13 - a03 * a12, + b06 = a20 * a31 - a21 * a30, + b07 = a20 * a32 - a22 * a30, + b08 = a20 * a33 - a23 * a30, + b09 = a21 * a32 - a22 * a31, + b10 = a21 * a33 - a23 * a31, + b11 = a22 * a33 - a23 * a32; + + // Calculate the determinant + return b00 * b11 - b01 * b10 + b02 * b09 + b03 * b08 - b04 * b07 + b05 * b06; +}; + +/** + * Multiplies two mat4's + * + * @param {mat4} out the receiving matrix + * @param {mat4} a the first operand + * @param {mat4} b the second operand + * @returns {mat4} out + */ +mat4.multiply = function (out, a, b) { + var a00 = a[0], a01 = a[1], a02 = a[2], a03 = a[3], + a10 = a[4], a11 = a[5], a12 = a[6], a13 = a[7], + a20 = a[8], a21 = a[9], a22 = a[10], a23 = a[11], + a30 = a[12], a31 = a[13], a32 = a[14], a33 = a[15]; + + // Cache only the current line of the second matrix + var b0 = b[0], b1 = b[1], b2 = b[2], b3 = b[3]; + out[0] = b0*a00 + b1*a10 + b2*a20 + b3*a30; + out[1] = b0*a01 + b1*a11 + b2*a21 + b3*a31; + out[2] = b0*a02 + b1*a12 + b2*a22 + b3*a32; + out[3] = b0*a03 + b1*a13 + b2*a23 + b3*a33; + + b0 = b[4]; b1 = b[5]; b2 = b[6]; b3 = b[7]; + out[4] = b0*a00 + b1*a10 + b2*a20 + b3*a30; + out[5] = b0*a01 + b1*a11 + b2*a21 + b3*a31; + out[6] = b0*a02 + b1*a12 + b2*a22 + b3*a32; + out[7] = b0*a03 + b1*a13 + b2*a23 + b3*a33; + + b0 = b[8]; b1 = b[9]; b2 = b[10]; b3 = b[11]; + out[8] = b0*a00 + b1*a10 + b2*a20 + b3*a30; + out[9] = b0*a01 + b1*a11 + b2*a21 + b3*a31; + out[10] = b0*a02 + b1*a12 + b2*a22 + b3*a32; + out[11] = b0*a03 + b1*a13 + b2*a23 + b3*a33; + + b0 = b[12]; b1 = b[13]; b2 = b[14]; b3 = b[15]; + out[12] = b0*a00 + b1*a10 + b2*a20 + b3*a30; + out[13] = b0*a01 + b1*a11 + b2*a21 + b3*a31; + out[14] = b0*a02 + b1*a12 + b2*a22 + b3*a32; + out[15] = b0*a03 + b1*a13 + b2*a23 + b3*a33; + return out; +}; + +/** + * Alias for {@link mat4.multiply} + * @function + */ +mat4.mul = mat4.multiply; + +/** + * Translate a mat4 by the given vector + * + * @param {mat4} out the receiving matrix + * @param {mat4} a the matrix to translate + * @param {vec3} v vector to translate by + * @returns {mat4} out + */ +mat4.translate = function (out, a, v) { + var x = v[0], y = v[1], z = v[2], + a00, a01, a02, a03, + a10, a11, a12, a13, + a20, a21, a22, a23; + + if (a === out) { + out[12] = a[0] * x + a[4] * y + a[8] * z + a[12]; + out[13] = a[1] * x + a[5] * y + a[9] * z + a[13]; + out[14] = a[2] * x + a[6] * y + a[10] * z + a[14]; + out[15] = a[3] * x + a[7] * y + a[11] * z + a[15]; + } else { + a00 = a[0]; a01 = a[1]; a02 = a[2]; a03 = a[3]; + a10 = a[4]; a11 = a[5]; a12 = a[6]; a13 = a[7]; + a20 = a[8]; a21 = a[9]; a22 = a[10]; a23 = a[11]; + + out[0] = a00; out[1] = a01; out[2] = a02; out[3] = a03; + out[4] = a10; out[5] = a11; out[6] = a12; out[7] = a13; + out[8] = a20; out[9] = a21; out[10] = a22; out[11] = a23; + + out[12] = a00 * x + a10 * y + a20 * z + a[12]; + out[13] = a01 * x + a11 * y + a21 * z + a[13]; + out[14] = a02 * x + a12 * y + a22 * z + a[14]; + out[15] = a03 * x + a13 * y + a23 * z + a[15]; + } + + return out; +}; + +/** + * Scales the mat4 by the dimensions in the given vec3 + * + * @param {mat4} out the receiving matrix + * @param {mat4} a the matrix to scale + * @param {vec3} v the vec3 to scale the matrix by + * @returns {mat4} out + **/ +mat4.scale = function(out, a, v) { + var x = v[0], y = v[1], z = v[2]; + + out[0] = a[0] * x; + out[1] = a[1] * x; + out[2] = a[2] * x; + out[3] = a[3] * x; + out[4] = a[4] * y; + out[5] = a[5] * y; + out[6] = a[6] * y; + out[7] = a[7] * y; + out[8] = a[8] * z; + out[9] = a[9] * z; + out[10] = a[10] * z; + out[11] = a[11] * z; + out[12] = a[12]; + out[13] = a[13]; + out[14] = a[14]; + out[15] = a[15]; + return out; +}; + +/** + * Rotates a mat4 by the given angle + * + * @param {mat4} out the receiving matrix + * @param {mat4} a the matrix to rotate + * @param {Number} rad the angle to rotate the matrix by + * @param {vec3} axis the axis to rotate around + * @returns {mat4} out + */ +mat4.rotate = function (out, a, rad, axis) { + var x = axis[0], y = axis[1], z = axis[2], + len = Math.sqrt(x * x + y * y + z * z), + s, c, t, + a00, a01, a02, a03, + a10, a11, a12, a13, + a20, a21, a22, a23, + b00, b01, b02, + b10, b11, b12, + b20, b21, b22; + + if (Math.abs(len) < GLMAT_EPSILON) { return null; } + + len = 1 / len; + x *= len; + y *= len; + z *= len; + + s = Math.sin(rad); + c = Math.cos(rad); + t = 1 - c; + + a00 = a[0]; a01 = a[1]; a02 = a[2]; a03 = a[3]; + a10 = a[4]; a11 = a[5]; a12 = a[6]; a13 = a[7]; + a20 = a[8]; a21 = a[9]; a22 = a[10]; a23 = a[11]; + + // Construct the elements of the rotation matrix + b00 = x * x * t + c; b01 = y * x * t + z * s; b02 = z * x * t - y * s; + b10 = x * y * t - z * s; b11 = y * y * t + c; b12 = z * y * t + x * s; + b20 = x * z * t + y * s; b21 = y * z * t - x * s; b22 = z * z * t + c; + + // Perform rotation-specific matrix multiplication + out[0] = a00 * b00 + a10 * b01 + a20 * b02; + out[1] = a01 * b00 + a11 * b01 + a21 * b02; + out[2] = a02 * b00 + a12 * b01 + a22 * b02; + out[3] = a03 * b00 + a13 * b01 + a23 * b02; + out[4] = a00 * b10 + a10 * b11 + a20 * b12; + out[5] = a01 * b10 + a11 * b11 + a21 * b12; + out[6] = a02 * b10 + a12 * b11 + a22 * b12; + out[7] = a03 * b10 + a13 * b11 + a23 * b12; + out[8] = a00 * b20 + a10 * b21 + a20 * b22; + out[9] = a01 * b20 + a11 * b21 + a21 * b22; + out[10] = a02 * b20 + a12 * b21 + a22 * b22; + out[11] = a03 * b20 + a13 * b21 + a23 * b22; + + if (a !== out) { // If the source and destination differ, copy the unchanged last row + out[12] = a[12]; + out[13] = a[13]; + out[14] = a[14]; + out[15] = a[15]; + } + return out; +}; + +/** + * Rotates a matrix by the given angle around the X axis + * + * @param {mat4} out the receiving matrix + * @param {mat4} a the matrix to rotate + * @param {Number} rad the angle to rotate the matrix by + * @returns {mat4} out + */ +mat4.rotateX = function (out, a, rad) { + var s = Math.sin(rad), + c = Math.cos(rad), + a10 = a[4], + a11 = a[5], + a12 = a[6], + a13 = a[7], + a20 = a[8], + a21 = a[9], + a22 = a[10], + a23 = a[11]; + + if (a !== out) { // If the source and destination differ, copy the unchanged rows + out[0] = a[0]; + out[1] = a[1]; + out[2] = a[2]; + out[3] = a[3]; + out[12] = a[12]; + out[13] = a[13]; + out[14] = a[14]; + out[15] = a[15]; + } + + // Perform axis-specific matrix multiplication + out[4] = a10 * c + a20 * s; + out[5] = a11 * c + a21 * s; + out[6] = a12 * c + a22 * s; + out[7] = a13 * c + a23 * s; + out[8] = a20 * c - a10 * s; + out[9] = a21 * c - a11 * s; + out[10] = a22 * c - a12 * s; + out[11] = a23 * c - a13 * s; + return out; +}; + +/** + * Rotates a matrix by the given angle around the Y axis + * + * @param {mat4} out the receiving matrix + * @param {mat4} a the matrix to rotate + * @param {Number} rad the angle to rotate the matrix by + * @returns {mat4} out + */ +mat4.rotateY = function (out, a, rad) { + var s = Math.sin(rad), + c = Math.cos(rad), + a00 = a[0], + a01 = a[1], + a02 = a[2], + a03 = a[3], + a20 = a[8], + a21 = a[9], + a22 = a[10], + a23 = a[11]; + + if (a !== out) { // If the source and destination differ, copy the unchanged rows + out[4] = a[4]; + out[5] = a[5]; + out[6] = a[6]; + out[7] = a[7]; + out[12] = a[12]; + out[13] = a[13]; + out[14] = a[14]; + out[15] = a[15]; + } + + // Perform axis-specific matrix multiplication + out[0] = a00 * c - a20 * s; + out[1] = a01 * c - a21 * s; + out[2] = a02 * c - a22 * s; + out[3] = a03 * c - a23 * s; + out[8] = a00 * s + a20 * c; + out[9] = a01 * s + a21 * c; + out[10] = a02 * s + a22 * c; + out[11] = a03 * s + a23 * c; + return out; +}; + +/** + * Rotates a matrix by the given angle around the Z axis + * + * @param {mat4} out the receiving matrix + * @param {mat4} a the matrix to rotate + * @param {Number} rad the angle to rotate the matrix by + * @returns {mat4} out + */ +mat4.rotateZ = function (out, a, rad) { + var s = Math.sin(rad), + c = Math.cos(rad), + a00 = a[0], + a01 = a[1], + a02 = a[2], + a03 = a[3], + a10 = a[4], + a11 = a[5], + a12 = a[6], + a13 = a[7]; + + if (a !== out) { // If the source and destination differ, copy the unchanged last row + out[8] = a[8]; + out[9] = a[9]; + out[10] = a[10]; + out[11] = a[11]; + out[12] = a[12]; + out[13] = a[13]; + out[14] = a[14]; + out[15] = a[15]; + } + + // Perform axis-specific matrix multiplication + out[0] = a00 * c + a10 * s; + out[1] = a01 * c + a11 * s; + out[2] = a02 * c + a12 * s; + out[3] = a03 * c + a13 * s; + out[4] = a10 * c - a00 * s; + out[5] = a11 * c - a01 * s; + out[6] = a12 * c - a02 * s; + out[7] = a13 * c - a03 * s; + return out; +}; + +/** + * Creates a matrix from a quaternion rotation and vector translation + * This is equivalent to (but much faster than): + * + * mat4.identity(dest); + * mat4.translate(dest, vec); + * var quatMat = mat4.create(); + * quat4.toMat4(quat, quatMat); + * mat4.multiply(dest, quatMat); + * + * @param {mat4} out mat4 receiving operation result + * @param {quat4} q Rotation quaternion + * @param {vec3} v Translation vector + * @returns {mat4} out + */ +mat4.fromRotationTranslation = function (out, q, v) { + // Quaternion math + var x = q[0], y = q[1], z = q[2], w = q[3], + x2 = x + x, + y2 = y + y, + z2 = z + z, + + xx = x * x2, + xy = x * y2, + xz = x * z2, + yy = y * y2, + yz = y * z2, + zz = z * z2, + wx = w * x2, + wy = w * y2, + wz = w * z2; + + out[0] = 1 - (yy + zz); + out[1] = xy + wz; + out[2] = xz - wy; + out[3] = 0; + out[4] = xy - wz; + out[5] = 1 - (xx + zz); + out[6] = yz + wx; + out[7] = 0; + out[8] = xz + wy; + out[9] = yz - wx; + out[10] = 1 - (xx + yy); + out[11] = 0; + out[12] = v[0]; + out[13] = v[1]; + out[14] = v[2]; + out[15] = 1; + + return out; +}; + +/** +* Calculates a 4x4 matrix from the given quaternion +* +* @param {mat4} out mat4 receiving operation result +* @param {quat} q Quaternion to create matrix from +* +* @returns {mat4} out +*/ +mat4.fromQuat = function (out, q) { + var x = q[0], y = q[1], z = q[2], w = q[3], + x2 = x + x, + y2 = y + y, + z2 = z + z, + + xx = x * x2, + xy = x * y2, + xz = x * z2, + yy = y * y2, + yz = y * z2, + zz = z * z2, + wx = w * x2, + wy = w * y2, + wz = w * z2; + + out[0] = 1 - (yy + zz); + out[1] = xy + wz; + out[2] = xz - wy; + out[3] = 0; + + out[4] = xy - wz; + out[5] = 1 - (xx + zz); + out[6] = yz + wx; + out[7] = 0; + + out[8] = xz + wy; + out[9] = yz - wx; + out[10] = 1 - (xx + yy); + out[11] = 0; + + out[12] = 0; + out[13] = 0; + out[14] = 0; + out[15] = 1; + + return out; +}; + +/** + * Generates a frustum matrix with the given bounds + * + * @param {mat4} out mat4 frustum matrix will be written into + * @param {Number} left Left bound of the frustum + * @param {Number} right Right bound of the frustum + * @param {Number} bottom Bottom bound of the frustum + * @param {Number} top Top bound of the frustum + * @param {Number} near Near bound of the frustum + * @param {Number} far Far bound of the frustum + * @returns {mat4} out + */ +mat4.frustum = function (out, left, right, bottom, top, near, far) { + var rl = 1 / (right - left), + tb = 1 / (top - bottom), + nf = 1 / (near - far); + out[0] = (near * 2) * rl; + out[1] = 0; + out[2] = 0; + out[3] = 0; + out[4] = 0; + out[5] = (near * 2) * tb; + out[6] = 0; + out[7] = 0; + out[8] = (right + left) * rl; + out[9] = (top + bottom) * tb; + out[10] = (far + near) * nf; + out[11] = -1; + out[12] = 0; + out[13] = 0; + out[14] = (far * near * 2) * nf; + out[15] = 0; + return out; +}; + +/** + * Generates a perspective projection matrix with the given bounds + * + * @param {mat4} out mat4 frustum matrix will be written into + * @param {number} fovy Vertical field of view in radians + * @param {number} aspect Aspect ratio. typically viewport width/height + * @param {number} near Near bound of the frustum + * @param {number} far Far bound of the frustum + * @returns {mat4} out + */ +mat4.perspective = function (out, fovy, aspect, near, far) { + var f = 1.0 / Math.tan(fovy / 2), + nf = 1 / (near - far); + out[0] = f / aspect; + out[1] = 0; + out[2] = 0; + out[3] = 0; + out[4] = 0; + out[5] = f; + out[6] = 0; + out[7] = 0; + out[8] = 0; + out[9] = 0; + out[10] = (far + near) * nf; + out[11] = -1; + out[12] = 0; + out[13] = 0; + out[14] = (2 * far * near) * nf; + out[15] = 0; + return out; +}; + +/** + * Generates a orthogonal projection matrix with the given bounds + * + * @param {mat4} out mat4 frustum matrix will be written into + * @param {number} left Left bound of the frustum + * @param {number} right Right bound of the frustum + * @param {number} bottom Bottom bound of the frustum + * @param {number} top Top bound of the frustum + * @param {number} near Near bound of the frustum + * @param {number} far Far bound of the frustum + * @returns {mat4} out + */ +mat4.ortho = function (out, left, right, bottom, top, near, far) { + var lr = 1 / (left - right), + bt = 1 / (bottom - top), + nf = 1 / (near - far); + out[0] = -2 * lr; + out[1] = 0; + out[2] = 0; + out[3] = 0; + out[4] = 0; + out[5] = -2 * bt; + out[6] = 0; + out[7] = 0; + out[8] = 0; + out[9] = 0; + out[10] = 2 * nf; + out[11] = 0; + out[12] = (left + right) * lr; + out[13] = (top + bottom) * bt; + out[14] = (far + near) * nf; + out[15] = 1; + return out; +}; + +/** + * Generates a look-at matrix with the given eye position, focal point, and up axis + * + * @param {mat4} out mat4 frustum matrix will be written into + * @param {vec3} eye Position of the viewer + * @param {vec3} center Point the viewer is looking at + * @param {vec3} up vec3 pointing up + * @returns {mat4} out + */ +mat4.lookAt = function (out, eye, center, up) { + var x0, x1, x2, y0, y1, y2, z0, z1, z2, len, + eyex = eye[0], + eyey = eye[1], + eyez = eye[2], + upx = up[0], + upy = up[1], + upz = up[2], + centerx = center[0], + centery = center[1], + centerz = center[2]; + + if (Math.abs(eyex - centerx) < GLMAT_EPSILON && + Math.abs(eyey - centery) < GLMAT_EPSILON && + Math.abs(eyez - centerz) < GLMAT_EPSILON) { + return mat4.identity(out); + } + + z0 = eyex - centerx; + z1 = eyey - centery; + z2 = eyez - centerz; + + len = 1 / Math.sqrt(z0 * z0 + z1 * z1 + z2 * z2); + z0 *= len; + z1 *= len; + z2 *= len; + + x0 = upy * z2 - upz * z1; + x1 = upz * z0 - upx * z2; + x2 = upx * z1 - upy * z0; + len = Math.sqrt(x0 * x0 + x1 * x1 + x2 * x2); + if (!len) { + x0 = 0; + x1 = 0; + x2 = 0; + } else { + len = 1 / len; + x0 *= len; + x1 *= len; + x2 *= len; + } + + y0 = z1 * x2 - z2 * x1; + y1 = z2 * x0 - z0 * x2; + y2 = z0 * x1 - z1 * x0; + + len = Math.sqrt(y0 * y0 + y1 * y1 + y2 * y2); + if (!len) { + y0 = 0; + y1 = 0; + y2 = 0; + } else { + len = 1 / len; + y0 *= len; + y1 *= len; + y2 *= len; + } + + out[0] = x0; + out[1] = y0; + out[2] = z0; + out[3] = 0; + out[4] = x1; + out[5] = y1; + out[6] = z1; + out[7] = 0; + out[8] = x2; + out[9] = y2; + out[10] = z2; + out[11] = 0; + out[12] = -(x0 * eyex + x1 * eyey + x2 * eyez); + out[13] = -(y0 * eyex + y1 * eyey + y2 * eyez); + out[14] = -(z0 * eyex + z1 * eyey + z2 * eyez); + out[15] = 1; + + return out; +}; + +/** + * Returns a string representation of a mat4 + * + * @param {mat4} mat matrix to represent as a string + * @returns {String} string representation of the matrix + */ +mat4.str = function (a) { + return 'mat4(' + a[0] + ', ' + a[1] + ', ' + a[2] + ', ' + a[3] + ', ' + + a[4] + ', ' + a[5] + ', ' + a[6] + ', ' + a[7] + ', ' + + a[8] + ', ' + a[9] + ', ' + a[10] + ', ' + a[11] + ', ' + + a[12] + ', ' + a[13] + ', ' + a[14] + ', ' + a[15] + ')'; +}; + +export default mat4; diff --git a/src/globe/beam/glMatrix/old/quat.js b/src/globe/beam/glMatrix/old/quat.js new file mode 100755 index 0000000..f3987f3 --- /dev/null +++ b/src/globe/beam/glMatrix/old/quat.js @@ -0,0 +1,531 @@ +import {GLMAT_ARRAY_TYPE} from "./common"; +import vec3 from "./vec3"; +import vec4 from "./vec4"; +import mat3 from "./mat3"; + +/* Copyright (c) 2013, Brandon Jones, Colin MacKenzie IV. All rights reserved. + +Redistribution and use in source and binary forms, with or without modification, +are permitted provided that the following conditions are met: + + * Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR +ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ + +/** + * @class Quaternion + * @name quat + */ +var quat = {}; + +/** + * Creates a new identity quat + * + * @returns {quat} a new quaternion + */ +quat.create = function() { + var out = new GLMAT_ARRAY_TYPE(4); + out[0] = 0; + out[1] = 0; + out[2] = 0; + out[3] = 1; + return out; +}; + +/** + * Sets a quaternion to represent the shortest rotation from one + * vector to another. + * + * Both vectors are assumed to be unit length. + * + * @param {quat} out the receiving quaternion. + * @param {vec3} a the initial vector + * @param {vec3} b the destination vector + * @returns {quat} out + */ +quat.rotationTo = (function() { + var tmpvec3 = vec3.create(); + var xUnitVec3 = vec3.fromValues(1,0,0); + var yUnitVec3 = vec3.fromValues(0,1,0); + + return function(out, a, b) { + var dot = vec3.dot(a, b); + if (dot < -0.999999) { + vec3.cross(tmpvec3, xUnitVec3, a); + if (vec3.length(tmpvec3) < 0.000001) + vec3.cross(tmpvec3, yUnitVec3, a); + vec3.normalize(tmpvec3, tmpvec3); + quat.setAxisAngle(out, tmpvec3, Math.PI); + return out; + } else if (dot > 0.999999) { + out[0] = 0; + out[1] = 0; + out[2] = 0; + out[3] = 1; + return out; + } else { + vec3.cross(tmpvec3, a, b); + out[0] = tmpvec3[0]; + out[1] = tmpvec3[1]; + out[2] = tmpvec3[2]; + out[3] = 1 + dot; + return quat.normalize(out, out); + } + }; +})(); + +/** + * Sets the specified quaternion with values corresponding to the given + * axes. Each axis is a vec3 and is expected to be unit length and + * perpendicular to all other specified axes. + * + * @param {vec3} view the vector representing the viewing direction + * @param {vec3} right the vector representing the local "right" direction + * @param {vec3} up the vector representing the local "up" direction + * @returns {quat} out + */ +quat.setAxes = (function() { + var matr = mat3.create(); + + return function(out, view, right, up) { + matr[0] = right[0]; + matr[3] = right[1]; + matr[6] = right[2]; + + matr[1] = up[0]; + matr[4] = up[1]; + matr[7] = up[2]; + + matr[2] = view[0]; + matr[5] = view[1]; + matr[8] = view[2]; + + return quat.normalize(out, quat.fromMat3(out, matr)); + }; +})(); + +/** + * Creates a new quat initialized with values from an existing quaternion + * + * @param {quat} a quaternion to clone + * @returns {quat} a new quaternion + * @function + */ +quat.clone = vec4.clone; + +/** + * Creates a new quat initialized with the given values + * + * @param {Number} x X component + * @param {Number} y Y component + * @param {Number} z Z component + * @param {Number} w W component + * @returns {quat} a new quaternion + * @function + */ +quat.fromValues = vec4.fromValues; + +/** + * Copy the values from one quat to another + * + * @param {quat} out the receiving quaternion + * @param {quat} a the source quaternion + * @returns {quat} out + * @function + */ +quat.copy = vec4.copy; + +/** + * Set the components of a quat to the given values + * + * @param {quat} out the receiving quaternion + * @param {Number} x X component + * @param {Number} y Y component + * @param {Number} z Z component + * @param {Number} w W component + * @returns {quat} out + * @function + */ +quat.set = vec4.set; + +/** + * Set a quat to the identity quaternion + * + * @param {quat} out the receiving quaternion + * @returns {quat} out + */ +quat.identity = function(out) { + out[0] = 0; + out[1] = 0; + out[2] = 0; + out[3] = 1; + return out; +}; + +/** + * Sets a quat from the given angle and rotation axis, + * then returns it. + * + * @param {quat} out the receiving quaternion + * @param {vec3} axis the axis around which to rotate + * @param {Number} rad the angle in radians + * @returns {quat} out + **/ +quat.setAxisAngle = function(out, axis, rad) { + rad = rad * 0.5; + var s = Math.sin(rad); + out[0] = s * axis[0]; + out[1] = s * axis[1]; + out[2] = s * axis[2]; + out[3] = Math.cos(rad); + return out; +}; + +/** + * Adds two quat's + * + * @param {quat} out the receiving quaternion + * @param {quat} a the first operand + * @param {quat} b the second operand + * @returns {quat} out + * @function + */ +quat.add = vec4.add; + +/** + * Multiplies two quat's + * + * @param {quat} out the receiving quaternion + * @param {quat} a the first operand + * @param {quat} b the second operand + * @returns {quat} out + */ +quat.multiply = function(out, a, b) { + var ax = a[0], ay = a[1], az = a[2], aw = a[3], + bx = b[0], by = b[1], bz = b[2], bw = b[3]; + + out[0] = ax * bw + aw * bx + ay * bz - az * by; + out[1] = ay * bw + aw * by + az * bx - ax * bz; + out[2] = az * bw + aw * bz + ax * by - ay * bx; + out[3] = aw * bw - ax * bx - ay * by - az * bz; + return out; +}; + +/** + * Alias for {@link quat.multiply} + * @function + */ +quat.mul = quat.multiply; + +/** + * Scales a quat by a scalar number + * + * @param {quat} out the receiving vector + * @param {quat} a the vector to scale + * @param {Number} b amount to scale the vector by + * @returns {quat} out + * @function + */ +quat.scale = vec4.scale; + +/** + * Rotates a quaternion by the given angle about the X axis + * + * @param {quat} out quat receiving operation result + * @param {quat} a quat to rotate + * @param {number} rad angle (in radians) to rotate + * @returns {quat} out + */ +quat.rotateX = function (out, a, rad) { + rad *= 0.5; + + var ax = a[0], ay = a[1], az = a[2], aw = a[3], + bx = Math.sin(rad), bw = Math.cos(rad); + + out[0] = ax * bw + aw * bx; + out[1] = ay * bw + az * bx; + out[2] = az * bw - ay * bx; + out[3] = aw * bw - ax * bx; + return out; +}; + +/** + * Rotates a quaternion by the given angle about the Y axis + * + * @param {quat} out quat receiving operation result + * @param {quat} a quat to rotate + * @param {number} rad angle (in radians) to rotate + * @returns {quat} out + */ +quat.rotateY = function (out, a, rad) { + rad *= 0.5; + + var ax = a[0], ay = a[1], az = a[2], aw = a[3], + by = Math.sin(rad), bw = Math.cos(rad); + + out[0] = ax * bw - az * by; + out[1] = ay * bw + aw * by; + out[2] = az * bw + ax * by; + out[3] = aw * bw - ay * by; + return out; +}; + +/** + * Rotates a quaternion by the given angle about the Z axis + * + * @param {quat} out quat receiving operation result + * @param {quat} a quat to rotate + * @param {number} rad angle (in radians) to rotate + * @returns {quat} out + */ +quat.rotateZ = function (out, a, rad) { + rad *= 0.5; + + var ax = a[0], ay = a[1], az = a[2], aw = a[3], + bz = Math.sin(rad), bw = Math.cos(rad); + + out[0] = ax * bw + ay * bz; + out[1] = ay * bw - ax * bz; + out[2] = az * bw + aw * bz; + out[3] = aw * bw - az * bz; + return out; +}; + +/** + * Calculates the W component of a quat from the X, Y, and Z components. + * Assumes that quaternion is 1 unit in length. + * Any existing W component will be ignored. + * + * @param {quat} out the receiving quaternion + * @param {quat} a quat to calculate W component of + * @returns {quat} out + */ +quat.calculateW = function (out, a) { + var x = a[0], y = a[1], z = a[2]; + + out[0] = x; + out[1] = y; + out[2] = z; + out[3] = -Math.sqrt(Math.abs(1.0 - x * x - y * y - z * z)); + return out; +}; + +/** + * Calculates the dot product of two quat's + * + * @param {quat} a the first operand + * @param {quat} b the second operand + * @returns {Number} dot product of a and b + * @function + */ +quat.dot = vec4.dot; + +/** + * Performs a linear interpolation between two quat's + * + * @param {quat} out the receiving quaternion + * @param {quat} a the first operand + * @param {quat} b the second operand + * @param {Number} t interpolation amount between the two inputs + * @returns {quat} out + * @function + */ +quat.lerp = vec4.lerp; + +/** + * Performs a spherical linear interpolation between two quat + * + * @param {quat} out the receiving quaternion + * @param {quat} a the first operand + * @param {quat} b the second operand + * @param {Number} t interpolation amount between the two inputs + * @returns {quat} out + */ +quat.slerp = function (out, a, b, t) { + // benchmarks: + // http://jsperf.com/quaternion-slerp-implementations + + var ax = a[0], ay = a[1], az = a[2], aw = a[3], + bx = b[0], by = b[1], bz = b[2], bw = b[3]; + + var omega, cosom, sinom, scale0, scale1; + + // calc cosine + cosom = ax * bx + ay * by + az * bz + aw * bw; + // adjust signs (if necessary) + if ( cosom < 0.0 ) { + cosom = -cosom; + bx = - bx; + by = - by; + bz = - bz; + bw = - bw; + } + // calculate coefficients + if ( (1.0 - cosom) > 0.000001 ) { + // standard case (slerp) + omega = Math.acos(cosom); + sinom = Math.sin(omega); + scale0 = Math.sin((1.0 - t) * omega) / sinom; + scale1 = Math.sin(t * omega) / sinom; + } else { + // "from" and "to" quaternions are very close + // ... so we can do a linear interpolation + scale0 = 1.0 - t; + scale1 = t; + } + // calculate final values + out[0] = scale0 * ax + scale1 * bx; + out[1] = scale0 * ay + scale1 * by; + out[2] = scale0 * az + scale1 * bz; + out[3] = scale0 * aw + scale1 * bw; + + return out; +}; + +/** + * Calculates the inverse of a quat + * + * @param {quat} out the receiving quaternion + * @param {quat} a quat to calculate inverse of + * @returns {quat} out + */ +quat.invert = function(out, a) { + var a0 = a[0], a1 = a[1], a2 = a[2], a3 = a[3], + dot = a0*a0 + a1*a1 + a2*a2 + a3*a3, + invDot = dot ? 1.0/dot : 0; + + // TODO: Would be faster to return [0,0,0,0] immediately if dot == 0 + + out[0] = -a0*invDot; + out[1] = -a1*invDot; + out[2] = -a2*invDot; + out[3] = a3*invDot; + return out; +}; + +/** + * Calculates the conjugate of a quat + * If the quaternion is normalized, this function is faster than quat.inverse and produces the same result. + * + * @param {quat} out the receiving quaternion + * @param {quat} a quat to calculate conjugate of + * @returns {quat} out + */ +quat.conjugate = function (out, a) { + out[0] = -a[0]; + out[1] = -a[1]; + out[2] = -a[2]; + out[3] = a[3]; + return out; +}; + +/** + * Calculates the length of a quat + * + * @param {quat} a vector to calculate length of + * @returns {Number} length of a + * @function + */ +quat.length = vec4.length; + +/** + * Alias for {@link quat.length} + * @function + */ +quat.len = quat.length; + +/** + * Calculates the squared length of a quat + * + * @param {quat} a vector to calculate squared length of + * @returns {Number} squared length of a + * @function + */ +quat.squaredLength = vec4.squaredLength; + +/** + * Alias for {@link quat.squaredLength} + * @function + */ +quat.sqrLen = quat.squaredLength; + +/** + * Normalize a quat + * + * @param {quat} out the receiving quaternion + * @param {quat} a quaternion to normalize + * @returns {quat} out + * @function + */ +quat.normalize = vec4.normalize; + +/** + * Creates a quaternion from the given 3x3 rotation matrix. + * + * NOTE: The resultant quaternion is not normalized, so you should be sure + * to renormalize the quaternion yourself where necessary. + * + * @param {quat} out the receiving quaternion + * @param {mat3} m rotation matrix + * @returns {quat} out + * @function + */ +quat.fromMat3 = function(out, m) { + // Algorithm in Ken Shoemake's article in 1987 SIGGRAPH course notes + // article "Quaternion Calculus and Fast Animation". + var fTrace = m[0] + m[4] + m[8]; + var fRoot; + + if ( fTrace > 0.0 ) { + // |w| > 1/2, may as well choose w > 1/2 + fRoot = Math.sqrt(fTrace + 1.0); // 2w + out[3] = 0.5 * fRoot; + fRoot = 0.5/fRoot; // 1/(4w) + out[0] = (m[7]-m[5])*fRoot; + out[1] = (m[2]-m[6])*fRoot; + out[2] = (m[3]-m[1])*fRoot; + } else { + // |w| <= 1/2 + var i = 0; + if ( m[4] > m[0] ) + i = 1; + if ( m[8] > m[i*3+i] ) + i = 2; + var j = (i+1)%3; + var k = (i+2)%3; + + fRoot = Math.sqrt(m[i*3+i]-m[j*3+j]-m[k*3+k] + 1.0); + out[i] = 0.5 * fRoot; + fRoot = 0.5 / fRoot; + out[3] = (m[k*3+j] - m[j*3+k]) * fRoot; + out[j] = (m[j*3+i] + m[i*3+j]) * fRoot; + out[k] = (m[k*3+i] + m[i*3+k]) * fRoot; + } + + return out; +}; + +/** + * Returns a string representation of a quatenion + * + * @param {quat} vec vector to represent as a string + * @returns {String} string representation of the vector + */ +quat.str = function (a) { + return 'quat(' + a[0] + ', ' + a[1] + ', ' + a[2] + ', ' + a[3] + ')'; +}; + +export default quat; \ No newline at end of file diff --git a/src/globe/beam/glMatrix/old/vec2.js b/src/globe/beam/glMatrix/old/vec2.js new file mode 100755 index 0000000..9d04152 --- /dev/null +++ b/src/globe/beam/glMatrix/old/vec2.js @@ -0,0 +1,538 @@ +import {GLMAT_ARRAY_TYPE} from "./common"; +import {GLMAT_RANDOM} from "./common"; + +/* Copyright (c) 2013, Brandon Jones, Colin MacKenzie IV. All rights reserved. + +Redistribution and use in source and binary forms, with or without modification, +are permitted provided that the following conditions are met: + + * Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR +ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ + +/** + * @class 2 Dimensional Vector + * @name vec2 + */ +var vec2 = {}; + +/** + * Creates a new, empty vec2 + * + * @returns {vec2} a new 2D vector + */ +vec2.create = function() { + var out = new GLMAT_ARRAY_TYPE(2); + out[0] = 0; + out[1] = 0; + return out; +}; + +/** + * Creates a new vec2 initialized with values from an existing vector + * + * @param {vec2} a vector to clone + * @returns {vec2} a new 2D vector + */ +vec2.clone = function(a) { + var out = new GLMAT_ARRAY_TYPE(2); + out[0] = a[0]; + out[1] = a[1]; + return out; +}; + +/** + * Creates a new vec2 initialized with the given values + * + * @param {Number} x X component + * @param {Number} y Y component + * @returns {vec2} a new 2D vector + */ +vec2.fromValues = function(x, y) { + var out = new GLMAT_ARRAY_TYPE(2); + out[0] = x; + out[1] = y; + return out; +}; + +/** + * Copy the values from one vec2 to another + * + * @param {vec2} out the receiving vector + * @param {vec2} a the source vector + * @returns {vec2} out + */ +vec2.copy = function(out, a) { + out[0] = a[0]; + out[1] = a[1]; + return out; +}; + +/** + * Set the components of a vec2 to the given values + * + * @param {vec2} out the receiving vector + * @param {Number} x X component + * @param {Number} y Y component + * @returns {vec2} out + */ +vec2.set = function(out, x, y) { + out[0] = x; + out[1] = y; + return out; +}; + +/** + * Adds two vec2's + * + * @param {vec2} out the receiving vector + * @param {vec2} a the first operand + * @param {vec2} b the second operand + * @returns {vec2} out + */ +vec2.add = function(out, a, b) { + out[0] = a[0] + b[0]; + out[1] = a[1] + b[1]; + return out; +}; + +/** + * Subtracts vector b from vector a + * + * @param {vec2} out the receiving vector + * @param {vec2} a the first operand + * @param {vec2} b the second operand + * @returns {vec2} out + */ +vec2.subtract = function(out, a, b) { + out[0] = a[0] - b[0]; + out[1] = a[1] - b[1]; + return out; +}; + +/** + * Alias for {@link vec2.subtract} + * @function + */ +vec2.sub = vec2.subtract; + +/** + * Multiplies two vec2's + * + * @param {vec2} out the receiving vector + * @param {vec2} a the first operand + * @param {vec2} b the second operand + * @returns {vec2} out + */ +vec2.multiply = function(out, a, b) { + out[0] = a[0] * b[0]; + out[1] = a[1] * b[1]; + return out; +}; + +/** + * Alias for {@link vec2.multiply} + * @function + */ +vec2.mul = vec2.multiply; + + +/** + * Divides two vec2's + * + * @param {vec2} out the receiving vector + * @param {vec2} a the first operand + * @param {vec2} b the second operand + * @returns {vec2} out + */ +vec2.divide = function(out, a, b) { + out[0] = a[0] / b[0]; + out[1] = a[1] / b[1]; + return out; +}; + +/** + * Alias for {@link vec2.divide} + * @function + */ +vec2.div = vec2.divide; + +/** + * Returns the minimum of two vec2's + * + * @param {vec2} out the receiving vector + * @param {vec2} a the first operand + * @param {vec2} b the second operand + * @returns {vec2} out + */ +vec2.min = function(out, a, b) { + out[0] = Math.min(a[0], b[0]); + out[1] = Math.min(a[1], b[1]); + return out; +}; + +/** + * Returns the maximum of two vec2's + * + * @param {vec2} out the receiving vector + * @param {vec2} a the first operand + * @param {vec2} b the second operand + * @returns {vec2} out + */ +vec2.max = function(out, a, b) { + out[0] = Math.max(a[0], b[0]); + out[1] = Math.max(a[1], b[1]); + return out; +}; + +/** + * Scales a vec2 by a scalar number + * + * @param {vec2} out the receiving vector + * @param {vec2} a the vector to scale + * @param {Number} b amount to scale the vector by + * @returns {vec2} out + */ +vec2.scale = function(out, a, b) { + out[0] = a[0] * b; + out[1] = a[1] * b; + return out; +}; + +/** + * Adds two vec2's after scaling the second operand by a scalar value + * + * @param {vec2} out the receiving vector + * @param {vec2} a the first operand + * @param {vec2} b the second operand + * @param {Number} scale the amount to scale b by before adding + * @returns {vec2} out + */ +vec2.scaleAndAdd = function(out, a, b, scale) { + out[0] = a[0] + (b[0] * scale); + out[1] = a[1] + (b[1] * scale); + return out; +}; + +/** + * Calculates the euclidian distance between two vec2's + * + * @param {vec2} a the first operand + * @param {vec2} b the second operand + * @returns {Number} distance between a and b + */ +vec2.distance = function(a, b) { + var x = b[0] - a[0], + y = b[1] - a[1]; + return Math.sqrt(x*x + y*y); +}; + +/** + * Alias for {@link vec2.distance} + * @function + */ +vec2.dist = vec2.distance; + +/** + * Calculates the squared euclidian distance between two vec2's + * + * @param {vec2} a the first operand + * @param {vec2} b the second operand + * @returns {Number} squared distance between a and b + */ +vec2.squaredDistance = function(a, b) { + var x = b[0] - a[0], + y = b[1] - a[1]; + return x*x + y*y; +}; + +/** + * Alias for {@link vec2.squaredDistance} + * @function + */ +vec2.sqrDist = vec2.squaredDistance; + +/** + * Calculates the length of a vec2 + * + * @param {vec2} a vector to calculate length of + * @returns {Number} length of a + */ +vec2.length = function (a) { + var x = a[0], + y = a[1]; + return Math.sqrt(x*x + y*y); +}; + +/** + * Alias for {@link vec2.length} + * @function + */ +vec2.len = vec2.length; + +/** + * Calculates the squared length of a vec2 + * + * @param {vec2} a vector to calculate squared length of + * @returns {Number} squared length of a + */ +vec2.squaredLength = function (a) { + var x = a[0], + y = a[1]; + return x*x + y*y; +}; + +/** + * Alias for {@link vec2.squaredLength} + * @function + */ +vec2.sqrLen = vec2.squaredLength; + +/** + * Negates the components of a vec2 + * + * @param {vec2} out the receiving vector + * @param {vec2} a vector to negate + * @returns {vec2} out + */ +vec2.negate = function(out, a) { + out[0] = -a[0]; + out[1] = -a[1]; + return out; +}; + +/** + * Normalize a vec2 + * + * @param {vec2} out the receiving vector + * @param {vec2} a vector to normalize + * @returns {vec2} out + */ +vec2.normalize = function(out, a) { + var x = a[0], + y = a[1]; + var len = x*x + y*y; + if (len > 0) { + //TODO: evaluate use of glm_invsqrt here? + len = 1 / Math.sqrt(len); + out[0] = a[0] * len; + out[1] = a[1] * len; + } + return out; +}; + +/** + * Calculates the dot product of two vec2's + * + * @param {vec2} a the first operand + * @param {vec2} b the second operand + * @returns {Number} dot product of a and b + */ +vec2.dot = function (a, b) { + return a[0] * b[0] + a[1] * b[1]; +}; + +/** + * Computes the cross product of two vec2's + * Note that the cross product must by definition produce a 3D vector + * + * @param {vec3} out the receiving vector + * @param {vec2} a the first operand + * @param {vec2} b the second operand + * @returns {vec3} out + */ +vec2.cross = function(out, a, b) { + var z = a[0] * b[1] - a[1] * b[0]; + out[0] = out[1] = 0; + out[2] = z; + return out; +}; + +/** + * Performs a linear interpolation between two vec2's + * + * @param {vec2} out the receiving vector + * @param {vec2} a the first operand + * @param {vec2} b the second operand + * @param {Number} t interpolation amount between the two inputs + * @returns {vec2} out + */ +vec2.lerp = function (out, a, b, t) { + var ax = a[0], + ay = a[1]; + out[0] = ax + t * (b[0] - ax); + out[1] = ay + t * (b[1] - ay); + return out; +}; + +/** + * Generates a random vector with the given scale + * + * @param {vec2} out the receiving vector + * @param {Number} [scale] Length of the resulting vector. If ommitted, a unit vector will be returned + * @returns {vec2} out + */ +vec2.random = function (out, scale) { + scale = scale || 1.0; + var r = GLMAT_RANDOM() * 2.0 * Math.PI; + out[0] = Math.cos(r) * scale; + out[1] = Math.sin(r) * scale; + return out; +}; + +/** + * Transforms the vec2 with a mat2 + * + * @param {vec2} out the receiving vector + * @param {vec2} a the vector to transform + * @param {mat2} m matrix to transform with + * @returns {vec2} out + */ +vec2.transformMat2 = function(out, a, m) { + var x = a[0], + y = a[1]; + out[0] = m[0] * x + m[2] * y; + out[1] = m[1] * x + m[3] * y; + return out; +}; + +/** + * Transforms the vec2 with a mat2d + * + * @param {vec2} out the receiving vector + * @param {vec2} a the vector to transform + * @param {mat2d} m matrix to transform with + * @returns {vec2} out + */ +vec2.transformMat2d = function(out, a, m) { + var x = a[0], + y = a[1]; + out[0] = m[0] * x + m[2] * y + m[4]; + out[1] = m[1] * x + m[3] * y + m[5]; + return out; +}; + +/** + * Transforms the vec2 with a mat3 + * 3rd vector component is implicitly '1' + * + * @param {vec2} out the receiving vector + * @param {vec2} a the vector to transform + * @param {mat3} m matrix to transform with + * @returns {vec2} out + */ +vec2.transformMat3 = function(out, a, m) { + var x = a[0], + y = a[1]; + out[0] = m[0] * x + m[3] * y + m[6]; + out[1] = m[1] * x + m[4] * y + m[7]; + return out; +}; + +/** + * Transforms the vec2 with a mat4 + * 3rd vector component is implicitly '0' + * 4th vector component is implicitly '1' + * + * @param {vec2} out the receiving vector + * @param {vec2} a the vector to transform + * @param {mat4} m matrix to transform with + * @returns {vec2} out + */ +vec2.transformMat4 = function(out, a, m) { + var x = a[0], + y = a[1]; + out[0] = m[0] * x + m[4] * y + m[12]; + out[1] = m[1] * x + m[5] * y + m[13]; + return out; +}; + +/** + * Perform some operation over an array of vec2s. + * + * @param {Array} a the array of vectors to iterate over + * @param {Number} stride Number of elements between the start of each vec2. If 0 assumes tightly packed + * @param {Number} offset Number of elements to skip at the beginning of the array + * @param {Number} count Number of vec2s to iterate over. If 0 iterates over entire array + * @param {Function} fn Function to call for each vector in the array + * @param {Object} [arg] additional argument to pass to fn + * @returns {Array} a + * @function + */ +vec2.forEach = (function() { + var vec = vec2.create(); + + return function(a, stride, offset, count, fn, arg) { + var i, l; + if(!stride) { + stride = 2; + } + + if(!offset) { + offset = 0; + } + + if(count) { + l = Math.min((count * stride) + offset, a.length); + } else { + l = a.length; + } + + for(i = offset; i < l; i += stride) { + vec[0] = a[i]; vec[1] = a[i+1]; + fn(vec, vec, arg); + a[i] = vec[0]; a[i+1] = vec[1]; + } + + return a; + }; +})(); + +/** + * Returns a string representation of a vector + * + * @param {vec2} vec vector to represent as a string + * @returns {String} string representation of the vector + */ +vec2.str = function (a) { + return 'vec2(' + a[0] + ', ' + a[1] + ')'; +}; + + + + + +vec2.multiplyScalar = function(out, a, b) { + out[0] = a[0] * b; + out[1] = a[1] * b; + return out; +}; + +vec2.clear = function(out) { + out[0] = 0; + out[1] = 0; + return out; +}; + +vec2.addXY = function(out, a, x, y) { + out[0] = a[0] + x; + out[1] = a[1] + y; + return out; +}; + + +export default vec2; + diff --git a/src/globe/beam/glMatrix/old/vec3.js b/src/globe/beam/glMatrix/old/vec3.js new file mode 100755 index 0000000..1f8374f --- /dev/null +++ b/src/globe/beam/glMatrix/old/vec3.js @@ -0,0 +1,562 @@ +import {GLMAT_ARRAY_TYPE} from "./common"; +import {GLMAT_RANDOM} from "./common"; + +/* Copyright (c) 2013, Brandon Jones, Colin MacKenzie IV. All rights reserved. + +Redistribution and use in source and binary forms, with or without modification, +are permitted provided that the following conditions are met: + + * Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR +ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ + +/** + * @class 3 Dimensional Vector + * @name vec3 + */ +var vec3 = {}; + +/** + * Creates a new, empty vec3 + * + * @returns {vec3} a new 3D vector + */ +vec3.create = function() { + var out = new GLMAT_ARRAY_TYPE(3); + out[0] = 0; + out[1] = 0; + out[2] = 0; + return out; +}; + +/** + * Creates a new vec3 initialized with values from an existing vector + * + * @param {vec3} a vector to clone + * @returns {vec3} a new 3D vector + */ +vec3.clone = function(a) { + var out = new GLMAT_ARRAY_TYPE(3); + out[0] = a[0]; + out[1] = a[1]; + out[2] = a[2]; + return out; +}; + +/** + * Creates a new vec3 initialized with the given values + * + * @param {Number} x X component + * @param {Number} y Y component + * @param {Number} z Z component + * @returns {vec3} a new 3D vector + */ +vec3.fromValues = function(x, y, z) { + var out = new GLMAT_ARRAY_TYPE(3); + out[0] = x; + out[1] = y; + out[2] = z; + return out; +}; + +/** + * Copy the values from one vec3 to another + * + * @param {vec3} out the receiving vector + * @param {vec3} a the source vector + * @returns {vec3} out + */ +vec3.copy = function(out, a) { + out[0] = a[0]; + out[1] = a[1]; + out[2] = a[2]; + return out; +}; + +/** + * Set the components of a vec3 to the given values + * + * @param {vec3} out the receiving vector + * @param {Number} x X component + * @param {Number} y Y component + * @param {Number} z Z component + * @returns {vec3} out + */ +vec3.set = function(out, x, y, z) { + out[0] = x; + out[1] = y; + out[2] = z; + return out; +}; + +/** + * Adds two vec3's + * + * @param {vec3} out the receiving vector + * @param {vec3} a the first operand + * @param {vec3} b the second operand + * @returns {vec3} out + */ +vec3.add = function(out, a, b) { + out[0] = a[0] + b[0]; + out[1] = a[1] + b[1]; + out[2] = a[2] + b[2]; + return out; +}; + +/** + * Subtracts vector b from vector a + * + * @param {vec3} out the receiving vector + * @param {vec3} a the first operand + * @param {vec3} b the second operand + * @returns {vec3} out + */ +vec3.subtract = function(out, a, b) { + out[0] = a[0] - b[0]; + out[1] = a[1] - b[1]; + out[2] = a[2] - b[2]; + return out; +}; + +/** + * Alias for {@link vec3.subtract} + * @function + */ +vec3.sub = vec3.subtract; + +/** + * Multiplies two vec3's + * + * @param {vec3} out the receiving vector + * @param {vec3} a the first operand + * @param {vec3} b the second operand + * @returns {vec3} out + */ +vec3.multiply = function(out, a, b) { + out[0] = a[0] * b[0]; + out[1] = a[1] * b[1]; + out[2] = a[2] * b[2]; + return out; +}; + +/** + * Alias for {@link vec3.multiply} + * @function + */ +vec3.mul = vec3.multiply; + +/** + * Divides two vec3's + * + * @param {vec3} out the receiving vector + * @param {vec3} a the first operand + * @param {vec3} b the second operand + * @returns {vec3} out + */ +vec3.divide = function(out, a, b) { + out[0] = a[0] / b[0]; + out[1] = a[1] / b[1]; + out[2] = a[2] / b[2]; + return out; +}; + +/** + * Alias for {@link vec3.divide} + * @function + */ +vec3.div = vec3.divide; + +/** + * Returns the minimum of two vec3's + * + * @param {vec3} out the receiving vector + * @param {vec3} a the first operand + * @param {vec3} b the second operand + * @returns {vec3} out + */ +vec3.min = function(out, a, b) { + out[0] = Math.min(a[0], b[0]); + out[1] = Math.min(a[1], b[1]); + out[2] = Math.min(a[2], b[2]); + return out; +}; + +/** + * Returns the maximum of two vec3's + * + * @param {vec3} out the receiving vector + * @param {vec3} a the first operand + * @param {vec3} b the second operand + * @returns {vec3} out + */ +vec3.max = function(out, a, b) { + out[0] = Math.max(a[0], b[0]); + out[1] = Math.max(a[1], b[1]); + out[2] = Math.max(a[2], b[2]); + return out; +}; + +/** + * Scales a vec3 by a scalar number + * + * @param {vec3} out the receiving vector + * @param {vec3} a the vector to scale + * @param {Number} b amount to scale the vector by + * @returns {vec3} out + */ +vec3.scale = function(out, a, b) { + out[0] = a[0] * b; + out[1] = a[1] * b; + out[2] = a[2] * b; + return out; +}; + +/** + * Adds two vec3's after scaling the second operand by a scalar value + * + * @param {vec3} out the receiving vector + * @param {vec3} a the first operand + * @param {vec3} b the second operand + * @param {Number} scale the amount to scale b by before adding + * @returns {vec3} out + */ +vec3.scaleAndAdd = function(out, a, b, scale) { + out[0] = a[0] + (b[0] * scale); + out[1] = a[1] + (b[1] * scale); + out[2] = a[2] + (b[2] * scale); + return out; +}; + +/** + * Calculates the euclidian distance between two vec3's + * + * @param {vec3} a the first operand + * @param {vec3} b the second operand + * @returns {Number} distance between a and b + */ +vec3.distance = function(a, b) { + var x = b[0] - a[0], + y = b[1] - a[1], + z = b[2] - a[2]; + return Math.sqrt(x*x + y*y + z*z); +}; + +/** + * Alias for {@link vec3.distance} + * @function + */ +vec3.dist = vec3.distance; + +/** + * Calculates the squared euclidian distance between two vec3's + * + * @param {vec3} a the first operand + * @param {vec3} b the second operand + * @returns {Number} squared distance between a and b + */ +vec3.squaredDistance = function(a, b) { + var x = b[0] - a[0], + y = b[1] - a[1], + z = b[2] - a[2]; + return x*x + y*y + z*z; +}; + +/** + * Alias for {@link vec3.squaredDistance} + * @function + */ +vec3.sqrDist = vec3.squaredDistance; + +/** + * Calculates the length of a vec3 + * + * @param {vec3} a vector to calculate length of + * @returns {Number} length of a + */ +vec3.length = function (a) { + var x = a[0], + y = a[1], + z = a[2]; + return Math.sqrt(x*x + y*y + z*z); +}; + +/** + * Alias for {@link vec3.length} + * @function + */ +vec3.len = vec3.length; + +/** + * Calculates the squared length of a vec3 + * + * @param {vec3} a vector to calculate squared length of + * @returns {Number} squared length of a + */ +vec3.squaredLength = function (a) { + var x = a[0], + y = a[1], + z = a[2]; + return x*x + y*y + z*z; +}; + +/** + * Alias for {@link vec3.squaredLength} + * @function + */ +vec3.sqrLen = vec3.squaredLength; + +/** + * Negates the components of a vec3 + * + * @param {vec3} out the receiving vector + * @param {vec3} a vector to negate + * @returns {vec3} out + */ +vec3.negate = function(out, a) { + out[0] = -a[0]; + out[1] = -a[1]; + out[2] = -a[2]; + return out; +}; + +/** + * Normalize a vec3 + * + * @param {vec3} out the receiving vector + * @param {vec3} a vector to normalize + * @returns {vec3} out + */ +vec3.normalize = function(out, a) { + var x = a[0], + y = a[1], + z = a[2]; + var len = x*x + y*y + z*z; + if (len > 0) { + //TODO: evaluate use of glm_invsqrt here? + len = 1 / Math.sqrt(len); + out[0] = a[0] * len; + out[1] = a[1] * len; + out[2] = a[2] * len; + } + return out; +}; + +/** + * Calculates the dot product of two vec3's + * + * @param {vec3} a the first operand + * @param {vec3} b the second operand + * @returns {Number} dot product of a and b + */ +vec3.dot = function (a, b) { + return a[0] * b[0] + a[1] * b[1] + a[2] * b[2]; +}; + +/** + * Computes the cross product of two vec3's + * + * @param {vec3} out the receiving vector + * @param {vec3} a the first operand + * @param {vec3} b the second operand + * @returns {vec3} out + */ +vec3.cross = function(out, a, b) { + var ax = a[0], ay = a[1], az = a[2], + bx = b[0], by = b[1], bz = b[2]; + + out[0] = ay * bz - az * by; + out[1] = az * bx - ax * bz; + out[2] = ax * by - ay * bx; + return out; +}; + +/** + * Performs a linear interpolation between two vec3's + * + * @param {vec3} out the receiving vector + * @param {vec3} a the first operand + * @param {vec3} b the second operand + * @param {Number} t interpolation amount between the two inputs + * @returns {vec3} out + */ +vec3.lerp = function (out, a, b, t) { + var ax = a[0], + ay = a[1], + az = a[2]; + out[0] = ax + t * (b[0] - ax); + out[1] = ay + t * (b[1] - ay); + out[2] = az + t * (b[2] - az); + return out; +}; + +/** + * Generates a random vector with the given scale + * + * @param {vec3} out the receiving vector + * @param {Number} [scale] Length of the resulting vector. If ommitted, a unit vector will be returned + * @returns {vec3} out + */ +vec3.random = function (out, scale) { + scale = scale || 1.0; + + var r = GLMAT_RANDOM() * 2.0 * Math.PI; + var z = (GLMAT_RANDOM() * 2.0) - 1.0; + var zScale = Math.sqrt(1.0-z*z) * scale; + + out[0] = Math.cos(r) * zScale; + out[1] = Math.sin(r) * zScale; + out[2] = z * scale; + return out; +}; + +/** + * Transforms the vec3 with a mat4. + * 4th vector component is implicitly '1' + * + * @param {vec3} out the receiving vector + * @param {vec3} a the vector to transform + * @param {mat4} m matrix to transform with + * @returns {vec3} out + */ +vec3.transformMat4 = function(out, a, m) { + var x = a[0], y = a[1], z = a[2]; + out[0] = m[0] * x + m[4] * y + m[8] * z + m[12]; + out[1] = m[1] * x + m[5] * y + m[9] * z + m[13]; + out[2] = m[2] * x + m[6] * y + m[10] * z + m[14]; + return out; +}; + +/** + * Transforms the vec3 with a mat3. + * + * @param {vec3} out the receiving vector + * @param {vec3} a the vector to transform + * @param {mat4} m the 3x3 matrix to transform with + * @returns {vec3} out + */ +vec3.transformMat3 = function(out, a, m) { + var x = a[0], y = a[1], z = a[2]; + out[0] = x * m[0] + y * m[3] + z * m[6]; + out[1] = x * m[1] + y * m[4] + z * m[7]; + out[2] = x * m[2] + y * m[5] + z * m[8]; + return out; +}; + +/** + * Transforms the vec3 with a quat + * + * @param {vec3} out the receiving vector + * @param {vec3} a the vector to transform + * @param {quat} q quaternion to transform with + * @returns {vec3} out + */ +vec3.transformQuat = function(out, a, q) { + // benchmarks: http://jsperf.com/quaternion-transform-vec3-implementations + + var x = a[0], y = a[1], z = a[2], + qx = q[0], qy = q[1], qz = q[2], qw = q[3], + + // calculate quat * vec + ix = qw * x + qy * z - qz * y, + iy = qw * y + qz * x - qx * z, + iz = qw * z + qx * y - qy * x, + iw = -qx * x - qy * y - qz * z; + + // calculate result * inverse quat + out[0] = ix * qw + iw * -qx + iy * -qz - iz * -qy; + out[1] = iy * qw + iw * -qy + iz * -qx - ix * -qz; + out[2] = iz * qw + iw * -qz + ix * -qy - iy * -qx; + return out; +}; + +/** + * Perform some operation over an array of vec3s. + * + * @param {Array} a the array of vectors to iterate over + * @param {Number} stride Number of elements between the start of each vec3. If 0 assumes tightly packed + * @param {Number} offset Number of elements to skip at the beginning of the array + * @param {Number} count Number of vec3s to iterate over. If 0 iterates over entire array + * @param {Function} fn Function to call for each vector in the array + * @param {Object} [arg] additional argument to pass to fn + * @returns {Array} a + * @function + */ +vec3.forEach = (function() { + var vec = vec3.create(); + + return function(a, stride, offset, count, fn, arg) { + var i, l; + if(!stride) { + stride = 3; + } + + if(!offset) { + offset = 0; + } + + if(count) { + l = Math.min((count * stride) + offset, a.length); + } else { + l = a.length; + } + + for(i = offset; i < l; i += stride) { + vec[0] = a[i]; vec[1] = a[i+1]; vec[2] = a[i+2]; + fn(vec, vec, arg); + a[i] = vec[0]; a[i+1] = vec[1]; a[i+2] = vec[2]; + } + + return a; + }; +})(); + +/** + * Returns a string representation of a vector + * + * @param {vec3} vec vector to represent as a string + * @returns {String} string representation of the vector + */ +vec3.str = function (a) { + return 'vec3(' + a[0] + ', ' + a[1] + ', ' + a[2] + ')'; +}; + + + +vec3.multiplyScalar = function(out, a, b) { + out[0] = a[0] * b; + out[1] = a[1] * b; + out[2] = a[2] * b; + return out; +}; + +vec3.clear = function(out) { + out[0] = 0; + out[1] = 0; + out[2] = 0; + return out; +}; + +vec3.addXYZ = function(out, a, x, y, z) { + out[0] = a[0] + x; + out[1] = a[1] + y; + out[2] = a[2] + z; + return out; +}; + + + +export default vec3; diff --git a/src/globe/beam/glMatrix/old/vec4.js b/src/globe/beam/glMatrix/old/vec4.js new file mode 100755 index 0000000..9cdad38 --- /dev/null +++ b/src/globe/beam/glMatrix/old/vec4.js @@ -0,0 +1,526 @@ +import {GLMAT_ARRAY_TYPE} from "./common"; +import {GLMAT_RANDOM} from "./common"; + +/* Copyright (c) 2013, Brandon Jones, Colin MacKenzie IV. All rights reserved. + +Redistribution and use in source and binary forms, with or without modification, +are permitted provided that the following conditions are met: + + * Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR +ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ + +/** + * @class 4 Dimensional Vector + * @name vec4 + */ +var vec4 = {}; + +/** + * Creates a new, empty vec4 + * + * @returns {vec4} a new 4D vector + */ +vec4.create = function() { + var out = new GLMAT_ARRAY_TYPE(4); + out[0] = 0; + out[1] = 0; + out[2] = 0; + out[3] = 0; + return out; +}; + +/** + * Creates a new vec4 initialized with values from an existing vector + * + * @param {vec4} a vector to clone + * @returns {vec4} a new 4D vector + */ +vec4.clone = function(a) { + var out = new GLMAT_ARRAY_TYPE(4); + out[0] = a[0]; + out[1] = a[1]; + out[2] = a[2]; + out[3] = a[3]; + return out; +}; + +/** + * Creates a new vec4 initialized with the given values + * + * @param {Number} x X component + * @param {Number} y Y component + * @param {Number} z Z component + * @param {Number} w W component + * @returns {vec4} a new 4D vector + */ +vec4.fromValues = function(x, y, z, w) { + var out = new GLMAT_ARRAY_TYPE(4); + out[0] = x; + out[1] = y; + out[2] = z; + out[3] = w; + return out; +}; + +/** + * Copy the values from one vec4 to another + * + * @param {vec4} out the receiving vector + * @param {vec4} a the source vector + * @returns {vec4} out + */ +vec4.copy = function(out, a) { + out[0] = a[0]; + out[1] = a[1]; + out[2] = a[2]; + out[3] = a[3]; + return out; +}; + +/** + * Set the components of a vec4 to the given values + * + * @param {vec4} out the receiving vector + * @param {Number} x X component + * @param {Number} y Y component + * @param {Number} z Z component + * @param {Number} w W component + * @returns {vec4} out + */ +vec4.set = function(out, x, y, z, w) { + out[0] = x; + out[1] = y; + out[2] = z; + out[3] = w; + return out; +}; + +/** + * Adds two vec4's + * + * @param {vec4} out the receiving vector + * @param {vec4} a the first operand + * @param {vec4} b the second operand + * @returns {vec4} out + */ +vec4.add = function(out, a, b) { + out[0] = a[0] + b[0]; + out[1] = a[1] + b[1]; + out[2] = a[2] + b[2]; + out[3] = a[3] + b[3]; + return out; +}; + +/** + * Subtracts vector b from vector a + * + * @param {vec4} out the receiving vector + * @param {vec4} a the first operand + * @param {vec4} b the second operand + * @returns {vec4} out + */ +vec4.subtract = function(out, a, b) { + out[0] = a[0] - b[0]; + out[1] = a[1] - b[1]; + out[2] = a[2] - b[2]; + out[3] = a[3] - b[3]; + return out; +}; + +/** + * Alias for {@link vec4.subtract} + * @function + */ +vec4.sub = vec4.subtract; + +/** + * Multiplies two vec4's + * + * @param {vec4} out the receiving vector + * @param {vec4} a the first operand + * @param {vec4} b the second operand + * @returns {vec4} out + */ +vec4.multiply = function(out, a, b) { + out[0] = a[0] * b[0]; + out[1] = a[1] * b[1]; + out[2] = a[2] * b[2]; + out[3] = a[3] * b[3]; + return out; +}; + +/** + * Alias for {@link vec4.multiply} + * @function + */ +vec4.mul = vec4.multiply; + +/** + * Divides two vec4's + * + * @param {vec4} out the receiving vector + * @param {vec4} a the first operand + * @param {vec4} b the second operand + * @returns {vec4} out + */ +vec4.divide = function(out, a, b) { + out[0] = a[0] / b[0]; + out[1] = a[1] / b[1]; + out[2] = a[2] / b[2]; + out[3] = a[3] / b[3]; + return out; +}; + +/** + * Alias for {@link vec4.divide} + * @function + */ +vec4.div = vec4.divide; + +/** + * Returns the minimum of two vec4's + * + * @param {vec4} out the receiving vector + * @param {vec4} a the first operand + * @param {vec4} b the second operand + * @returns {vec4} out + */ +vec4.min = function(out, a, b) { + out[0] = Math.min(a[0], b[0]); + out[1] = Math.min(a[1], b[1]); + out[2] = Math.min(a[2], b[2]); + out[3] = Math.min(a[3], b[3]); + return out; +}; + +/** + * Returns the maximum of two vec4's + * + * @param {vec4} out the receiving vector + * @param {vec4} a the first operand + * @param {vec4} b the second operand + * @returns {vec4} out + */ +vec4.max = function(out, a, b) { + out[0] = Math.max(a[0], b[0]); + out[1] = Math.max(a[1], b[1]); + out[2] = Math.max(a[2], b[2]); + out[3] = Math.max(a[3], b[3]); + return out; +}; + +/** + * Scales a vec4 by a scalar number + * + * @param {vec4} out the receiving vector + * @param {vec4} a the vector to scale + * @param {Number} b amount to scale the vector by + * @returns {vec4} out + */ +vec4.scale = function(out, a, b) { + out[0] = a[0] * b; + out[1] = a[1] * b; + out[2] = a[2] * b; + out[3] = a[3] * b; + return out; +}; + +/** + * Adds two vec4's after scaling the second operand by a scalar value + * + * @param {vec4} out the receiving vector + * @param {vec4} a the first operand + * @param {vec4} b the second operand + * @param {Number} scale the amount to scale b by before adding + * @returns {vec4} out + */ +vec4.scaleAndAdd = function(out, a, b, scale) { + out[0] = a[0] + (b[0] * scale); + out[1] = a[1] + (b[1] * scale); + out[2] = a[2] + (b[2] * scale); + out[3] = a[3] + (b[3] * scale); + return out; +}; + +/** + * Calculates the euclidian distance between two vec4's + * + * @param {vec4} a the first operand + * @param {vec4} b the second operand + * @returns {Number} distance between a and b + */ +vec4.distance = function(a, b) { + var x = b[0] - a[0], + y = b[1] - a[1], + z = b[2] - a[2], + w = b[3] - a[3]; + return Math.sqrt(x*x + y*y + z*z + w*w); +}; + +/** + * Alias for {@link vec4.distance} + * @function + */ +vec4.dist = vec4.distance; + +/** + * Calculates the squared euclidian distance between two vec4's + * + * @param {vec4} a the first operand + * @param {vec4} b the second operand + * @returns {Number} squared distance between a and b + */ +vec4.squaredDistance = function(a, b) { + var x = b[0] - a[0], + y = b[1] - a[1], + z = b[2] - a[2], + w = b[3] - a[3]; + return x*x + y*y + z*z + w*w; +}; + +/** + * Alias for {@link vec4.squaredDistance} + * @function + */ +vec4.sqrDist = vec4.squaredDistance; + +/** + * Calculates the length of a vec4 + * + * @param {vec4} a vector to calculate length of + * @returns {Number} length of a + */ +vec4.length = function (a) { + var x = a[0], + y = a[1], + z = a[2], + w = a[3]; + return Math.sqrt(x*x + y*y + z*z + w*w); +}; + +/** + * Alias for {@link vec4.length} + * @function + */ +vec4.len = vec4.length; + +/** + * Calculates the squared length of a vec4 + * + * @param {vec4} a vector to calculate squared length of + * @returns {Number} squared length of a + */ +vec4.squaredLength = function (a) { + var x = a[0], + y = a[1], + z = a[2], + w = a[3]; + return x*x + y*y + z*z + w*w; +}; + +/** + * Alias for {@link vec4.squaredLength} + * @function + */ +vec4.sqrLen = vec4.squaredLength; + +/** + * Negates the components of a vec4 + * + * @param {vec4} out the receiving vector + * @param {vec4} a vector to negate + * @returns {vec4} out + */ +vec4.negate = function(out, a) { + out[0] = -a[0]; + out[1] = -a[1]; + out[2] = -a[2]; + out[3] = -a[3]; + return out; +}; + +/** + * Normalize a vec4 + * + * @param {vec4} out the receiving vector + * @param {vec4} a vector to normalize + * @returns {vec4} out + */ +vec4.normalize = function(out, a) { + var x = a[0], + y = a[1], + z = a[2], + w = a[3]; + var len = x*x + y*y + z*z + w*w; + if (len > 0) { + len = 1 / Math.sqrt(len); + out[0] = a[0] * len; + out[1] = a[1] * len; + out[2] = a[2] * len; + out[3] = a[3] * len; + } + return out; +}; + +/** + * Calculates the dot product of two vec4's + * + * @param {vec4} a the first operand + * @param {vec4} b the second operand + * @returns {Number} dot product of a and b + */ +vec4.dot = function (a, b) { + return a[0] * b[0] + a[1] * b[1] + a[2] * b[2] + a[3] * b[3]; +}; + +/** + * Performs a linear interpolation between two vec4's + * + * @param {vec4} out the receiving vector + * @param {vec4} a the first operand + * @param {vec4} b the second operand + * @param {Number} t interpolation amount between the two inputs + * @returns {vec4} out + */ +vec4.lerp = function (out, a, b, t) { + var ax = a[0], + ay = a[1], + az = a[2], + aw = a[3]; + out[0] = ax + t * (b[0] - ax); + out[1] = ay + t * (b[1] - ay); + out[2] = az + t * (b[2] - az); + out[3] = aw + t * (b[3] - aw); + return out; +}; + +/** + * Generates a random vector with the given scale + * + * @param {vec4} out the receiving vector + * @param {Number} [scale] Length of the resulting vector. If ommitted, a unit vector will be returned + * @returns {vec4} out + */ +vec4.random = function (out, scale) { + scale = scale || 1.0; + + //TODO: This is a pretty awful way of doing this. Find something better. + out[0] = GLMAT_RANDOM(); + out[1] = GLMAT_RANDOM(); + out[2] = GLMAT_RANDOM(); + out[3] = GLMAT_RANDOM(); + vec4.normalize(out, out); + vec4.scale(out, out, scale); + return out; +}; + +/** + * Transforms the vec4 with a mat4. + * + * @param {vec4} out the receiving vector + * @param {vec4} a the vector to transform + * @param {mat4} m matrix to transform with + * @returns {vec4} out + */ +vec4.transformMat4 = function(out, a, m) { + var x = a[0], y = a[1], z = a[2], w = a[3]; + out[0] = m[0] * x + m[4] * y + m[8] * z + m[12] * w; + out[1] = m[1] * x + m[5] * y + m[9] * z + m[13] * w; + out[2] = m[2] * x + m[6] * y + m[10] * z + m[14] * w; + out[3] = m[3] * x + m[7] * y + m[11] * z + m[15] * w; + return out; +}; + +/** + * Transforms the vec4 with a quat + * + * @param {vec4} out the receiving vector + * @param {vec4} a the vector to transform + * @param {quat} q quaternion to transform with + * @returns {vec4} out + */ +vec4.transformQuat = function(out, a, q) { + var x = a[0], y = a[1], z = a[2], + qx = q[0], qy = q[1], qz = q[2], qw = q[3], + + // calculate quat * vec + ix = qw * x + qy * z - qz * y, + iy = qw * y + qz * x - qx * z, + iz = qw * z + qx * y - qy * x, + iw = -qx * x - qy * y - qz * z; + + // calculate result * inverse quat + out[0] = ix * qw + iw * -qx + iy * -qz - iz * -qy; + out[1] = iy * qw + iw * -qy + iz * -qx - ix * -qz; + out[2] = iz * qw + iw * -qz + ix * -qy - iy * -qx; + return out; +}; + +/** + * Perform some operation over an array of vec4s. + * + * @param {Array} a the array of vectors to iterate over + * @param {Number} stride Number of elements between the start of each vec4. If 0 assumes tightly packed + * @param {Number} offset Number of elements to skip at the beginning of the array + * @param {Number} count Number of vec2s to iterate over. If 0 iterates over entire array + * @param {Function} fn Function to call for each vector in the array + * @param {Object} [arg] additional argument to pass to fn + * @returns {Array} a + * @function + */ +vec4.forEach = (function() { + var vec = vec4.create(); + + return function(a, stride, offset, count, fn, arg) { + var i, l; + if(!stride) { + stride = 4; + } + + if(!offset) { + offset = 0; + } + + if(count) { + l = Math.min((count * stride) + offset, a.length); + } else { + l = a.length; + } + + for(i = offset; i < l; i += stride) { + vec[0] = a[i]; vec[1] = a[i+1]; vec[2] = a[i+2]; vec[3] = a[i+3]; + fn(vec, vec, arg); + a[i] = vec[0]; a[i+1] = vec[1]; a[i+2] = vec[2]; a[i+3] = vec[3]; + } + + return a; + }; +})(); + +/** + * Returns a string representation of a vector + * + * @param {vec4} vec vector to represent as a string + * @returns {String} string representation of the vector + */ +vec4.str = function (a) { + return 'vec4(' + a[0] + ', ' + a[1] + ', ' + a[2] + ', ' + a[3] + ')'; +}; + +export default vec4; + + diff --git a/src/globe/beam/glMatrix/quat.js b/src/globe/beam/glMatrix/quat.js new file mode 100755 index 0000000..03eeae0 --- /dev/null +++ b/src/globe/beam/glMatrix/quat.js @@ -0,0 +1,626 @@ +/* Copyright (c) 2015, Brandon Jones, Colin MacKenzie IV. + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. */ + +import * as glMatrix from "./common" +import * as mat3 from "./mat3" +import * as vec3 from "./vec3" +import * as vec4 from "./vec4" + +/** + * Quaternion + * @module quat + */ + +/** + * Creates a new identity quat + * + * @returns {quat} a new quaternion + */ +export function create() { + let out = new glMatrix.ARRAY_TYPE(4); + out[0] = 0; + out[1] = 0; + out[2] = 0; + out[3] = 1; + return out; +} + +/** + * Set a quat to the identity quaternion + * + * @param {quat} out the receiving quaternion + * @returns {quat} out + */ +export function identity(out) { + out[0] = 0; + out[1] = 0; + out[2] = 0; + out[3] = 1; + return out; +} + +/** + * Sets a quat from the given angle and rotation axis, + * then returns it. + * + * @param {quat} out the receiving quaternion + * @param {vec3} axis the axis around which to rotate + * @param {Number} rad the angle in radians + * @returns {quat} out + **/ +export function setAxisAngle(out, axis, rad) { + rad = rad * 0.5; + let s = Math.sin(rad); + out[0] = s * axis[0]; + out[1] = s * axis[1]; + out[2] = s * axis[2]; + out[3] = Math.cos(rad); + return out; +} + +/** + * Gets the rotation axis and angle for a given + * quaternion. If a quaternion is created with + * setAxisAngle, this method will return the same + * values as providied in the original parameter list + * OR functionally equivalent values. + * Example: The quaternion formed by axis [0, 0, 1] and + * angle -90 is the same as the quaternion formed by + * [0, 0, 1] and 270. This method favors the latter. + * @param {vec3} out_axis Vector receiving the axis of rotation + * @param {quat} q Quaternion to be decomposed + * @return {Number} Angle, in radians, of the rotation + */ +export function getAxisAngle(out_axis, q) { + let rad = Math.acos(q[3]) * 2.0; + let s = Math.sin(rad / 2.0); + if (s != 0.0) { + out_axis[0] = q[0] / s; + out_axis[1] = q[1] / s; + out_axis[2] = q[2] / s; + } else { + // If s is zero, return any axis (no rotation - axis does not matter) + out_axis[0] = 1; + out_axis[1] = 0; + out_axis[2] = 0; + } + return rad; +} + +/** + * Multiplies two quat's + * + * @param {quat} out the receiving quaternion + * @param {quat} a the first operand + * @param {quat} b the second operand + * @returns {quat} out + */ +export function multiply(out, a, b) { + let ax = a[0], ay = a[1], az = a[2], aw = a[3]; + let bx = b[0], by = b[1], bz = b[2], bw = b[3]; + + out[0] = ax * bw + aw * bx + ay * bz - az * by; + out[1] = ay * bw + aw * by + az * bx - ax * bz; + out[2] = az * bw + aw * bz + ax * by - ay * bx; + out[3] = aw * bw - ax * bx - ay * by - az * bz; + return out; +} + +/** + * Rotates a quaternion by the given angle about the X axis + * + * @param {quat} out quat receiving operation result + * @param {quat} a quat to rotate + * @param {number} rad angle (in radians) to rotate + * @returns {quat} out + */ +export function rotateX(out, a, rad) { + rad *= 0.5; + + let ax = a[0], ay = a[1], az = a[2], aw = a[3]; + let bx = Math.sin(rad), bw = Math.cos(rad); + + out[0] = ax * bw + aw * bx; + out[1] = ay * bw + az * bx; + out[2] = az * bw - ay * bx; + out[3] = aw * bw - ax * bx; + return out; +} + +/** + * Rotates a quaternion by the given angle about the Y axis + * + * @param {quat} out quat receiving operation result + * @param {quat} a quat to rotate + * @param {number} rad angle (in radians) to rotate + * @returns {quat} out + */ +export function rotateY(out, a, rad) { + rad *= 0.5; + + let ax = a[0], ay = a[1], az = a[2], aw = a[3]; + let by = Math.sin(rad), bw = Math.cos(rad); + + out[0] = ax * bw - az * by; + out[1] = ay * bw + aw * by; + out[2] = az * bw + ax * by; + out[3] = aw * bw - ay * by; + return out; +} + +/** + * Rotates a quaternion by the given angle about the Z axis + * + * @param {quat} out quat receiving operation result + * @param {quat} a quat to rotate + * @param {number} rad angle (in radians) to rotate + * @returns {quat} out + */ +export function rotateZ(out, a, rad) { + rad *= 0.5; + + let ax = a[0], ay = a[1], az = a[2], aw = a[3]; + let bz = Math.sin(rad), bw = Math.cos(rad); + + out[0] = ax * bw + ay * bz; + out[1] = ay * bw - ax * bz; + out[2] = az * bw + aw * bz; + out[3] = aw * bw - az * bz; + return out; +} + +/** + * Calculates the W component of a quat from the X, Y, and Z components. + * Assumes that quaternion is 1 unit in length. + * Any existing W component will be ignored. + * + * @param {quat} out the receiving quaternion + * @param {quat} a quat to calculate W component of + * @returns {quat} out + */ +export function calculateW(out, a) { + let x = a[0], y = a[1], z = a[2]; + + out[0] = x; + out[1] = y; + out[2] = z; + out[3] = Math.sqrt(Math.abs(1.0 - x * x - y * y - z * z)); + return out; +} + +/** + * Performs a spherical linear interpolation between two quat + * + * @param {quat} out the receiving quaternion + * @param {quat} a the first operand + * @param {quat} b the second operand + * @param {Number} t interpolation amount between the two inputs + * @returns {quat} out + */ +export function slerp(out, a, b, t) { + // benchmarks: + // http://jsperf.com/quaternion-slerp-implementations + let ax = a[0], ay = a[1], az = a[2], aw = a[3]; + let bx = b[0], by = b[1], bz = b[2], bw = b[3]; + + let omega, cosom, sinom, scale0, scale1; + + // calc cosine + cosom = ax * bx + ay * by + az * bz + aw * bw; + // adjust signs (if necessary) + if ( cosom < 0.0 ) { + cosom = -cosom; + bx = - bx; + by = - by; + bz = - bz; + bw = - bw; + } + // calculate coefficients + if ( (1.0 - cosom) > 0.000001 ) { + // standard case (slerp) + omega = Math.acos(cosom); + sinom = Math.sin(omega); + scale0 = Math.sin((1.0 - t) * omega) / sinom; + scale1 = Math.sin(t * omega) / sinom; + } else { + // "from" and "to" quaternions are very close + // ... so we can do a linear interpolation + scale0 = 1.0 - t; + scale1 = t; + } + // calculate final values + out[0] = scale0 * ax + scale1 * bx; + out[1] = scale0 * ay + scale1 * by; + out[2] = scale0 * az + scale1 * bz; + out[3] = scale0 * aw + scale1 * bw; + + return out; +} + +/** + * Calculates the inverse of a quat + * + * @param {quat} out the receiving quaternion + * @param {quat} a quat to calculate inverse of + * @returns {quat} out + */ +export function invert(out, a) { + let a0 = a[0], a1 = a[1], a2 = a[2], a3 = a[3]; + let dot = a0*a0 + a1*a1 + a2*a2 + a3*a3; + let invDot = dot ? 1.0/dot : 0; + + // TODO: Would be faster to return [0,0,0,0] immediately if dot == 0 + + out[0] = -a0*invDot; + out[1] = -a1*invDot; + out[2] = -a2*invDot; + out[3] = a3*invDot; + return out; +} + +/** + * Calculates the conjugate of a quat + * If the quaternion is normalized, this function is faster than quat.inverse and produces the same result. + * + * @param {quat} out the receiving quaternion + * @param {quat} a quat to calculate conjugate of + * @returns {quat} out + */ +export function conjugate(out, a) { + out[0] = -a[0]; + out[1] = -a[1]; + out[2] = -a[2]; + out[3] = a[3]; + return out; +} + +/** + * Creates a quaternion from the given 3x3 rotation matrix. + * + * NOTE: The resultant quaternion is not normalized, so you should be sure + * to renormalize the quaternion yourself where necessary. + * + * @param {quat} out the receiving quaternion + * @param {mat3} m rotation matrix + * @returns {quat} out + * @function + */ +export function fromMat3(out, m) { + // Algorithm in Ken Shoemake's article in 1987 SIGGRAPH course notes + // article "Quaternion Calculus and Fast Animation". + let fTrace = m[0] + m[4] + m[8]; + let fRoot; + + if ( fTrace > 0.0 ) { + // |w| > 1/2, may as well choose w > 1/2 + fRoot = Math.sqrt(fTrace + 1.0); // 2w + out[3] = 0.5 * fRoot; + fRoot = 0.5/fRoot; // 1/(4w) + out[0] = (m[5]-m[7])*fRoot; + out[1] = (m[6]-m[2])*fRoot; + out[2] = (m[1]-m[3])*fRoot; + } else { + // |w| <= 1/2 + let i = 0; + if ( m[4] > m[0] ) + i = 1; + if ( m[8] > m[i*3+i] ) + i = 2; + let j = (i+1)%3; + let k = (i+2)%3; + + fRoot = Math.sqrt(m[i*3+i]-m[j*3+j]-m[k*3+k] + 1.0); + out[i] = 0.5 * fRoot; + fRoot = 0.5 / fRoot; + out[3] = (m[j*3+k] - m[k*3+j]) * fRoot; + out[j] = (m[j*3+i] + m[i*3+j]) * fRoot; + out[k] = (m[k*3+i] + m[i*3+k]) * fRoot; + } + + return out; +} + +/** + * Creates a quaternion from the given euler angle x, y, z. + * + * @param {quat} out the receiving quaternion + * @param {x} Angle to rotate around X axis in degrees. + * @param {y} Angle to rotate around Y axis in degrees. + * @param {z} Angle to rotate around Z axis in degrees. + * @returns {quat} out + * @function + */ +export function fromEuler(out, x, y, z) { + let halfToRad = 0.5 * Math.PI / 180.0; + x *= halfToRad; + y *= halfToRad; + z *= halfToRad; + + let sx = Math.sin(x); + let cx = Math.cos(x); + let sy = Math.sin(y); + let cy = Math.cos(y); + let sz = Math.sin(z); + let cz = Math.cos(z); + + out[0] = sx * cy * cz - cx * sy * sz; + out[1] = cx * sy * cz + sx * cy * sz; + out[2] = cx * cy * sz - sx * sy * cz; + out[3] = cx * cy * cz + sx * sy * sz; + + return out; +} + +/** + * Returns a string representation of a quatenion + * + * @param {quat} a vector to represent as a string + * @returns {String} string representation of the vector + */ +export function str(a) { + return 'quat(' + a[0] + ', ' + a[1] + ', ' + a[2] + ', ' + a[3] + ')'; +} + +/** + * Creates a new quat initialized with values from an existing quaternion + * + * @param {quat} a quaternion to clone + * @returns {quat} a new quaternion + * @function + */ +export const clone = vec4.clone; + +/** + * Creates a new quat initialized with the given values + * + * @param {Number} x X component + * @param {Number} y Y component + * @param {Number} z Z component + * @param {Number} w W component + * @returns {quat} a new quaternion + * @function + */ +export const fromValues = vec4.fromValues; + +/** + * Copy the values from one quat to another + * + * @param {quat} out the receiving quaternion + * @param {quat} a the source quaternion + * @returns {quat} out + * @function + */ +export const copy = vec4.copy; + +/** + * Set the components of a quat to the given values + * + * @param {quat} out the receiving quaternion + * @param {Number} x X component + * @param {Number} y Y component + * @param {Number} z Z component + * @param {Number} w W component + * @returns {quat} out + * @function + */ +export const set = vec4.set; + +/** + * Adds two quat's + * + * @param {quat} out the receiving quaternion + * @param {quat} a the first operand + * @param {quat} b the second operand + * @returns {quat} out + * @function + */ +export const add = vec4.add; + +/** + * Alias for {@link quat.multiply} + * @function + */ +export const mul = multiply; + +/** + * Scales a quat by a scalar number + * + * @param {quat} out the receiving vector + * @param {quat} a the vector to scale + * @param {Number} b amount to scale the vector by + * @returns {quat} out + * @function + */ +export const scale = vec4.scale; + +/** + * Calculates the dot product of two quat's + * + * @param {quat} a the first operand + * @param {quat} b the second operand + * @returns {Number} dot product of a and b + * @function + */ +export const dot = vec4.dot; + +/** + * Performs a linear interpolation between two quat's + * + * @param {quat} out the receiving quaternion + * @param {quat} a the first operand + * @param {quat} b the second operand + * @param {Number} t interpolation amount between the two inputs + * @returns {quat} out + * @function + */ +export const lerp = vec4.lerp; + +/** + * Calculates the length of a quat + * + * @param {quat} a vector to calculate length of + * @returns {Number} length of a + */ +export const length = vec4.length; + +/** + * Alias for {@link quat.length} + * @function + */ +export const len = length; + +/** + * Calculates the squared length of a quat + * + * @param {quat} a vector to calculate squared length of + * @returns {Number} squared length of a + * @function + */ +export const squaredLength = vec4.squaredLength; + +/** + * Alias for {@link quat.squaredLength} + * @function + */ +export const sqrLen = squaredLength; + +/** + * Normalize a quat + * + * @param {quat} out the receiving quaternion + * @param {quat} a quaternion to normalize + * @returns {quat} out + * @function + */ +export const normalize = vec4.normalize; + +/** + * Returns whether or not the quaternions have exactly the same elements in the same position (when compared with ===) + * + * @param {quat} a The first quaternion. + * @param {quat} b The second quaternion. + * @returns {Boolean} True if the vectors are equal, false otherwise. + */ +export const exactEquals = vec4.exactEquals; + +/** + * Returns whether or not the quaternions have approximately the same elements in the same position. + * + * @param {quat} a The first vector. + * @param {quat} b The second vector. + * @returns {Boolean} True if the vectors are equal, false otherwise. + */ +export const equals = vec4.equals; + +/** + * Sets a quaternion to represent the shortest rotation from one + * vector to another. + * + * Both vectors are assumed to be unit length. + * + * @param {quat} out the receiving quaternion. + * @param {vec3} a the initial vector + * @param {vec3} b the destination vector + * @returns {quat} out + */ +export const rotationTo = (function() { + let tmpvec3 = vec3.create(); + let xUnitVec3 = vec3.fromValues(1,0,0); + let yUnitVec3 = vec3.fromValues(0,1,0); + + return function(out, a, b) { + let dot = vec3.dot(a, b); + if (dot < -0.999999) { + vec3.cross(tmpvec3, xUnitVec3, a); + if (vec3.len(tmpvec3) < 0.000001) + vec3.cross(tmpvec3, yUnitVec3, a); + vec3.normalize(tmpvec3, tmpvec3); + setAxisAngle(out, tmpvec3, Math.PI); + return out; + } else if (dot > 0.999999) { + out[0] = 0; + out[1] = 0; + out[2] = 0; + out[3] = 1; + return out; + } else { + vec3.cross(tmpvec3, a, b); + out[0] = tmpvec3[0]; + out[1] = tmpvec3[1]; + out[2] = tmpvec3[2]; + out[3] = 1 + dot; + return normalize(out, out); + } + }; +})(); + +/** + * Performs a spherical linear interpolation with two control points + * + * @param {quat} out the receiving quaternion + * @param {quat} a the first operand + * @param {quat} b the second operand + * @param {quat} c the third operand + * @param {quat} d the fourth operand + * @param {Number} t interpolation amount + * @returns {quat} out + */ +export const sqlerp = (function () { + let temp1 = create(); + let temp2 = create(); + + return function (out, a, b, c, d, t) { + slerp(temp1, a, d, t); + slerp(temp2, b, c, t); + slerp(out, temp1, temp2, 2 * t * (1 - t)); + + return out; + }; +}()); + +/** + * Sets the specified quaternion with values corresponding to the given + * axes. Each axis is a vec3 and is expected to be unit length and + * perpendicular to all other specified axes. + * + * @param {vec3} view the vector representing the viewing direction + * @param {vec3} right the vector representing the local "right" direction + * @param {vec3} up the vector representing the local "up" direction + * @returns {quat} out + */ +export const setAxes = (function() { + let matr = mat3.create(); + + return function(out, view, right, up) { + matr[0] = right[0]; + matr[3] = right[1]; + matr[6] = right[2]; + + matr[1] = up[0]; + matr[4] = up[1]; + matr[7] = up[2]; + + matr[2] = -view[0]; + matr[5] = -view[1]; + matr[8] = -view[2]; + + return normalize(out, fromMat3(out, matr)); + }; +})(); diff --git a/src/globe/beam/glMatrix/vec2.js b/src/globe/beam/glMatrix/vec2.js new file mode 100755 index 0000000..79b978b --- /dev/null +++ b/src/globe/beam/glMatrix/vec2.js @@ -0,0 +1,584 @@ +/* Copyright (c) 2015, Brandon Jones, Colin MacKenzie IV. + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. */ + +import * as glMatrix from "./common"; + +/** + * 2 Dimensional Vector + * @module vec2 + */ + +/** + * Creates a new, empty vec2 + * + * @returns {vec2} a new 2D vector + */ +export function create() { + let out = new glMatrix.ARRAY_TYPE(2); + out[0] = 0; + out[1] = 0; + return out; +} + +/** + * Creates a new vec2 initialized with values from an existing vector + * + * @param {vec2} a vector to clone + * @returns {vec2} a new 2D vector + */ +export function clone(a) { + let out = new glMatrix.ARRAY_TYPE(2); + out[0] = a[0]; + out[1] = a[1]; + return out; +} + +/** + * Creates a new vec2 initialized with the given values + * + * @param {Number} x X component + * @param {Number} y Y component + * @returns {vec2} a new 2D vector + */ +export function fromValues(x, y) { + let out = new glMatrix.ARRAY_TYPE(2); + out[0] = x; + out[1] = y; + return out; +} + +/** + * Copy the values from one vec2 to another + * + * @param {vec2} out the receiving vector + * @param {vec2} a the source vector + * @returns {vec2} out + */ +export function copy(out, a) { + out[0] = a[0]; + out[1] = a[1]; + return out; +} + +/** + * Set the components of a vec2 to the given values + * + * @param {vec2} out the receiving vector + * @param {Number} x X component + * @param {Number} y Y component + * @returns {vec2} out + */ +export function set(out, x, y) { + out[0] = x; + out[1] = y; + return out; +} + +/** + * Adds two vec2's + * + * @param {vec2} out the receiving vector + * @param {vec2} a the first operand + * @param {vec2} b the second operand + * @returns {vec2} out + */ +export function add(out, a, b) { + out[0] = a[0] + b[0]; + out[1] = a[1] + b[1]; + return out; +} + +/** + * Subtracts vector b from vector a + * + * @param {vec2} out the receiving vector + * @param {vec2} a the first operand + * @param {vec2} b the second operand + * @returns {vec2} out + */ +export function subtract(out, a, b) { + out[0] = a[0] - b[0]; + out[1] = a[1] - b[1]; + return out; +} + +/** + * Multiplies two vec2's + * + * @param {vec2} out the receiving vector + * @param {vec2} a the first operand + * @param {vec2} b the second operand + * @returns {vec2} out + */ +export function multiply(out, a, b) { + out[0] = a[0] * b[0]; + out[1] = a[1] * b[1]; + return out; +}; + +/** + * Divides two vec2's + * + * @param {vec2} out the receiving vector + * @param {vec2} a the first operand + * @param {vec2} b the second operand + * @returns {vec2} out + */ +export function divide(out, a, b) { + out[0] = a[0] / b[0]; + out[1] = a[1] / b[1]; + return out; +}; + +/** + * Math.ceil the components of a vec2 + * + * @param {vec2} out the receiving vector + * @param {vec2} a vector to ceil + * @returns {vec2} out + */ +export function ceil(out, a) { + out[0] = Math.ceil(a[0]); + out[1] = Math.ceil(a[1]); + return out; +}; + +/** + * Math.floor the components of a vec2 + * + * @param {vec2} out the receiving vector + * @param {vec2} a vector to floor + * @returns {vec2} out + */ +export function floor(out, a) { + out[0] = Math.floor(a[0]); + out[1] = Math.floor(a[1]); + return out; +}; + +/** + * Returns the minimum of two vec2's + * + * @param {vec2} out the receiving vector + * @param {vec2} a the first operand + * @param {vec2} b the second operand + * @returns {vec2} out + */ +export function min(out, a, b) { + out[0] = Math.min(a[0], b[0]); + out[1] = Math.min(a[1], b[1]); + return out; +}; + +/** + * Returns the maximum of two vec2's + * + * @param {vec2} out the receiving vector + * @param {vec2} a the first operand + * @param {vec2} b the second operand + * @returns {vec2} out + */ +export function max(out, a, b) { + out[0] = Math.max(a[0], b[0]); + out[1] = Math.max(a[1], b[1]); + return out; +}; + +/** + * Math.round the components of a vec2 + * + * @param {vec2} out the receiving vector + * @param {vec2} a vector to round + * @returns {vec2} out + */ +export function round (out, a) { + out[0] = Math.round(a[0]); + out[1] = Math.round(a[1]); + return out; +}; + +/** + * Scales a vec2 by a scalar number + * + * @param {vec2} out the receiving vector + * @param {vec2} a the vector to scale + * @param {Number} b amount to scale the vector by + * @returns {vec2} out + */ +export function scale(out, a, b) { + out[0] = a[0] * b; + out[1] = a[1] * b; + return out; +}; + +/** + * Adds two vec2's after scaling the second operand by a scalar value + * + * @param {vec2} out the receiving vector + * @param {vec2} a the first operand + * @param {vec2} b the second operand + * @param {Number} scale the amount to scale b by before adding + * @returns {vec2} out + */ +export function scaleAndAdd(out, a, b, scale) { + out[0] = a[0] + (b[0] * scale); + out[1] = a[1] + (b[1] * scale); + return out; +}; + +/** + * Calculates the euclidian distance between two vec2's + * + * @param {vec2} a the first operand + * @param {vec2} b the second operand + * @returns {Number} distance between a and b + */ +export function distance(a, b) { + var x = b[0] - a[0], + y = b[1] - a[1]; + return Math.sqrt(x*x + y*y); +}; + +/** + * Calculates the squared euclidian distance between two vec2's + * + * @param {vec2} a the first operand + * @param {vec2} b the second operand + * @returns {Number} squared distance between a and b + */ +export function squaredDistance(a, b) { + var x = b[0] - a[0], + y = b[1] - a[1]; + return x*x + y*y; +}; + +/** + * Calculates the length of a vec2 + * + * @param {vec2} a vector to calculate length of + * @returns {Number} length of a + */ +export function length(a) { + var x = a[0], + y = a[1]; + return Math.sqrt(x*x + y*y); +}; + +/** + * Calculates the squared length of a vec2 + * + * @param {vec2} a vector to calculate squared length of + * @returns {Number} squared length of a + */ +export function squaredLength (a) { + var x = a[0], + y = a[1]; + return x*x + y*y; +}; + +/** + * Negates the components of a vec2 + * + * @param {vec2} out the receiving vector + * @param {vec2} a vector to negate + * @returns {vec2} out + */ +export function negate(out, a) { + out[0] = -a[0]; + out[1] = -a[1]; + return out; +}; + +/** + * Returns the inverse of the components of a vec2 + * + * @param {vec2} out the receiving vector + * @param {vec2} a vector to invert + * @returns {vec2} out + */ +export function inverse(out, a) { + out[0] = 1.0 / a[0]; + out[1] = 1.0 / a[1]; + return out; +}; + +/** + * Normalize a vec2 + * + * @param {vec2} out the receiving vector + * @param {vec2} a vector to normalize + * @returns {vec2} out + */ +export function normalize(out, a) { + var x = a[0], + y = a[1]; + var len = x*x + y*y; + if (len > 0) { + //TODO: evaluate use of glm_invsqrt here? + len = 1 / Math.sqrt(len); + out[0] = a[0] * len; + out[1] = a[1] * len; + } + return out; +}; + +/** + * Calculates the dot product of two vec2's + * + * @param {vec2} a the first operand + * @param {vec2} b the second operand + * @returns {Number} dot product of a and b + */ +export function dot(a, b) { + return a[0] * b[0] + a[1] * b[1]; +}; + +/** + * Computes the cross product of two vec2's + * Note that the cross product must by definition produce a 3D vector + * + * @param {vec3} out the receiving vector + * @param {vec2} a the first operand + * @param {vec2} b the second operand + * @returns {vec3} out + */ +export function cross(out, a, b) { + var z = a[0] * b[1] - a[1] * b[0]; + out[0] = out[1] = 0; + out[2] = z; + return out; +}; + +/** + * Performs a linear interpolation between two vec2's + * + * @param {vec2} out the receiving vector + * @param {vec2} a the first operand + * @param {vec2} b the second operand + * @param {Number} t interpolation amount between the two inputs + * @returns {vec2} out + */ +export function lerp(out, a, b, t) { + var ax = a[0], + ay = a[1]; + out[0] = ax + t * (b[0] - ax); + out[1] = ay + t * (b[1] - ay); + return out; +}; + +/** + * Generates a random vector with the given scale + * + * @param {vec2} out the receiving vector + * @param {Number} [scale] Length of the resulting vector. If ommitted, a unit vector will be returned + * @returns {vec2} out + */ +export function random(out, scale) { + scale = scale || 1.0; + var r = glMatrix.RANDOM() * 2.0 * Math.PI; + out[0] = Math.cos(r) * scale; + out[1] = Math.sin(r) * scale; + return out; +}; + +/** + * Transforms the vec2 with a mat2 + * + * @param {vec2} out the receiving vector + * @param {vec2} a the vector to transform + * @param {mat2} m matrix to transform with + * @returns {vec2} out + */ +export function transformMat2(out, a, m) { + var x = a[0], + y = a[1]; + out[0] = m[0] * x + m[2] * y; + out[1] = m[1] * x + m[3] * y; + return out; +}; + +/** + * Transforms the vec2 with a mat2d + * + * @param {vec2} out the receiving vector + * @param {vec2} a the vector to transform + * @param {mat2d} m matrix to transform with + * @returns {vec2} out + */ +export function transformMat2d(out, a, m) { + var x = a[0], + y = a[1]; + out[0] = m[0] * x + m[2] * y + m[4]; + out[1] = m[1] * x + m[3] * y + m[5]; + return out; +}; + +/** + * Transforms the vec2 with a mat3 + * 3rd vector component is implicitly '1' + * + * @param {vec2} out the receiving vector + * @param {vec2} a the vector to transform + * @param {mat3} m matrix to transform with + * @returns {vec2} out + */ +export function transformMat3(out, a, m) { + var x = a[0], + y = a[1]; + out[0] = m[0] * x + m[3] * y + m[6]; + out[1] = m[1] * x + m[4] * y + m[7]; + return out; +}; + +/** + * Transforms the vec2 with a mat4 + * 3rd vector component is implicitly '0' + * 4th vector component is implicitly '1' + * + * @param {vec2} out the receiving vector + * @param {vec2} a the vector to transform + * @param {mat4} m matrix to transform with + * @returns {vec2} out + */ +export function transformMat4(out, a, m) { + let x = a[0]; + let y = a[1]; + out[0] = m[0] * x + m[4] * y + m[12]; + out[1] = m[1] * x + m[5] * y + m[13]; + return out; +} + +/** + * Returns a string representation of a vector + * + * @param {vec2} a vector to represent as a string + * @returns {String} string representation of the vector + */ +export function str(a) { + return 'vec2(' + a[0] + ', ' + a[1] + ')'; +} + +/** + * Returns whether or not the vectors exactly have the same elements in the same position (when compared with ===) + * + * @param {vec2} a The first vector. + * @param {vec2} b The second vector. + * @returns {Boolean} True if the vectors are equal, false otherwise. + */ +export function exactEquals(a, b) { + return a[0] === b[0] && a[1] === b[1]; +} + +/** + * Returns whether or not the vectors have approximately the same elements in the same position. + * + * @param {vec2} a The first vector. + * @param {vec2} b The second vector. + * @returns {Boolean} True if the vectors are equal, false otherwise. + */ +export function equals(a, b) { + let a0 = a[0], a1 = a[1]; + let b0 = b[0], b1 = b[1]; + return (Math.abs(a0 - b0) <= glMatrix.EPSILON*Math.max(1.0, Math.abs(a0), Math.abs(b0)) && + Math.abs(a1 - b1) <= glMatrix.EPSILON*Math.max(1.0, Math.abs(a1), Math.abs(b1))); +} + +/** + * Alias for {@link vec2.length} + * @function + */ +export const len = length; + +/** + * Alias for {@link vec2.subtract} + * @function + */ +export const sub = subtract; + +/** + * Alias for {@link vec2.multiply} + * @function + */ +export const mul = multiply; + +/** + * Alias for {@link vec2.divide} + * @function + */ +export const div = divide; + +/** + * Alias for {@link vec2.distance} + * @function + */ +export const dist = distance; + +/** + * Alias for {@link vec2.squaredDistance} + * @function + */ +export const sqrDist = squaredDistance; + +/** + * Alias for {@link vec2.squaredLength} + * @function + */ +export const sqrLen = squaredLength; + +/** + * Perform some operation over an array of vec2s. + * + * @param {Array} a the array of vectors to iterate over + * @param {Number} stride Number of elements between the start of each vec2. If 0 assumes tightly packed + * @param {Number} offset Number of elements to skip at the beginning of the array + * @param {Number} count Number of vec2s to iterate over. If 0 iterates over entire array + * @param {Function} fn Function to call for each vector in the array + * @param {Object} [arg] additional argument to pass to fn + * @returns {Array} a + * @function + */ +export const forEach = (function() { + let vec = create(); + + return function(a, stride, offset, count, fn, arg) { + let i, l; + if(!stride) { + stride = 2; + } + + if(!offset) { + offset = 0; + } + + if(count) { + l = Math.min((count * stride) + offset, a.length); + } else { + l = a.length; + } + + for(i = offset; i < l; i += stride) { + vec[0] = a[i]; vec[1] = a[i+1]; + fn(vec, vec, arg); + a[i] = vec[0]; a[i+1] = vec[1]; + } + + return a; + }; +})(); diff --git a/src/globe/beam/glMatrix/vec3.js b/src/globe/beam/glMatrix/vec3.js new file mode 100755 index 0000000..9c5ff8f --- /dev/null +++ b/src/globe/beam/glMatrix/vec3.js @@ -0,0 +1,776 @@ +/* Copyright (c) 2015, Brandon Jones, Colin MacKenzie IV. + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. */ + +import * as glMatrix from "./common"; + +/** + * 3 Dimensional Vector + * @module vec3 + */ + +/** + * Creates a new, empty vec3 + * + * @returns {vec3} a new 3D vector + */ +export function create() { + let out = new glMatrix.ARRAY_TYPE(3); + out[0] = 0; + out[1] = 0; + out[2] = 0; + return out; +} + +/** + * Creates a new vec3 initialized with values from an existing vector + * + * @param {vec3} a vector to clone + * @returns {vec3} a new 3D vector + */ +export function clone(a) { + var out = new glMatrix.ARRAY_TYPE(3); + out[0] = a[0]; + out[1] = a[1]; + out[2] = a[2]; + return out; +} + +/** + * Calculates the length of a vec3 + * + * @param {vec3} a vector to calculate length of + * @returns {Number} length of a + */ +export function length(a) { + let x = a[0]; + let y = a[1]; + let z = a[2]; + return Math.sqrt(x*x + y*y + z*z); +} + +/** + * Creates a new vec3 initialized with the given values + * + * @param {Number} x X component + * @param {Number} y Y component + * @param {Number} z Z component + * @returns {vec3} a new 3D vector + */ +export function fromValues(x, y, z) { + let out = new glMatrix.ARRAY_TYPE(3); + out[0] = x; + out[1] = y; + out[2] = z; + return out; +} + +/** + * Copy the values from one vec3 to another + * + * @param {vec3} out the receiving vector + * @param {vec3} a the source vector + * @returns {vec3} out + */ +export function copy(out, a) { + out[0] = a[0]; + out[1] = a[1]; + out[2] = a[2]; + return out; +} + +/** + * Set the components of a vec3 to the given values + * + * @param {vec3} out the receiving vector + * @param {Number} x X component + * @param {Number} y Y component + * @param {Number} z Z component + * @returns {vec3} out + */ +export function set(out, x, y, z) { + out[0] = x; + out[1] = y; + out[2] = z; + return out; +} + +/** + * Adds two vec3's + * + * @param {vec3} out the receiving vector + * @param {vec3} a the first operand + * @param {vec3} b the second operand + * @returns {vec3} out + */ +export function add(out, a, b) { + out[0] = a[0] + b[0]; + out[1] = a[1] + b[1]; + out[2] = a[2] + b[2]; + return out; +} + +/** + * Subtracts vector b from vector a + * + * @param {vec3} out the receiving vector + * @param {vec3} a the first operand + * @param {vec3} b the second operand + * @returns {vec3} out + */ +export function subtract(out, a, b) { + out[0] = a[0] - b[0]; + out[1] = a[1] - b[1]; + out[2] = a[2] - b[2]; + return out; +} + +/** + * Multiplies two vec3's + * + * @param {vec3} out the receiving vector + * @param {vec3} a the first operand + * @param {vec3} b the second operand + * @returns {vec3} out + */ +export function multiply(out, a, b) { + out[0] = a[0] * b[0]; + out[1] = a[1] * b[1]; + out[2] = a[2] * b[2]; + return out; +} + +/** + * Divides two vec3's + * + * @param {vec3} out the receiving vector + * @param {vec3} a the first operand + * @param {vec3} b the second operand + * @returns {vec3} out + */ +export function divide(out, a, b) { + out[0] = a[0] / b[0]; + out[1] = a[1] / b[1]; + out[2] = a[2] / b[2]; + return out; +} + +/** + * Math.ceil the components of a vec3 + * + * @param {vec3} out the receiving vector + * @param {vec3} a vector to ceil + * @returns {vec3} out + */ +export function ceil(out, a) { + out[0] = Math.ceil(a[0]); + out[1] = Math.ceil(a[1]); + out[2] = Math.ceil(a[2]); + return out; +} + +/** + * Math.floor the components of a vec3 + * + * @param {vec3} out the receiving vector + * @param {vec3} a vector to floor + * @returns {vec3} out + */ +export function floor(out, a) { + out[0] = Math.floor(a[0]); + out[1] = Math.floor(a[1]); + out[2] = Math.floor(a[2]); + return out; +} + +/** + * Returns the minimum of two vec3's + * + * @param {vec3} out the receiving vector + * @param {vec3} a the first operand + * @param {vec3} b the second operand + * @returns {vec3} out + */ +export function min(out, a, b) { + out[0] = Math.min(a[0], b[0]); + out[1] = Math.min(a[1], b[1]); + out[2] = Math.min(a[2], b[2]); + return out; +} + +/** + * Returns the maximum of two vec3's + * + * @param {vec3} out the receiving vector + * @param {vec3} a the first operand + * @param {vec3} b the second operand + * @returns {vec3} out + */ +export function max(out, a, b) { + out[0] = Math.max(a[0], b[0]); + out[1] = Math.max(a[1], b[1]); + out[2] = Math.max(a[2], b[2]); + return out; +} + +/** + * Math.round the components of a vec3 + * + * @param {vec3} out the receiving vector + * @param {vec3} a vector to round + * @returns {vec3} out + */ +export function round(out, a) { + out[0] = Math.round(a[0]); + out[1] = Math.round(a[1]); + out[2] = Math.round(a[2]); + return out; +} + +/** + * Scales a vec3 by a scalar number + * + * @param {vec3} out the receiving vector + * @param {vec3} a the vector to scale + * @param {Number} b amount to scale the vector by + * @returns {vec3} out + */ +export function scale(out, a, b) { + out[0] = a[0] * b; + out[1] = a[1] * b; + out[2] = a[2] * b; + return out; +} + +/** + * Adds two vec3's after scaling the second operand by a scalar value + * + * @param {vec3} out the receiving vector + * @param {vec3} a the first operand + * @param {vec3} b the second operand + * @param {Number} scale the amount to scale b by before adding + * @returns {vec3} out + */ +export function scaleAndAdd(out, a, b, scale) { + out[0] = a[0] + (b[0] * scale); + out[1] = a[1] + (b[1] * scale); + out[2] = a[2] + (b[2] * scale); + return out; +} + +/** + * Calculates the euclidian distance between two vec3's + * + * @param {vec3} a the first operand + * @param {vec3} b the second operand + * @returns {Number} distance between a and b + */ +export function distance(a, b) { + let x = b[0] - a[0]; + let y = b[1] - a[1]; + let z = b[2] - a[2]; + return Math.sqrt(x*x + y*y + z*z); +} + +/** + * Calculates the squared euclidian distance between two vec3's + * + * @param {vec3} a the first operand + * @param {vec3} b the second operand + * @returns {Number} squared distance between a and b + */ +export function squaredDistance(a, b) { + let x = b[0] - a[0]; + let y = b[1] - a[1]; + let z = b[2] - a[2]; + return x*x + y*y + z*z; +} + +/** + * Calculates the squared length of a vec3 + * + * @param {vec3} a vector to calculate squared length of + * @returns {Number} squared length of a + */ +export function squaredLength(a) { + let x = a[0]; + let y = a[1]; + let z = a[2]; + return x*x + y*y + z*z; +} + +/** + * Negates the components of a vec3 + * + * @param {vec3} out the receiving vector + * @param {vec3} a vector to negate + * @returns {vec3} out + */ +export function negate(out, a) { + out[0] = -a[0]; + out[1] = -a[1]; + out[2] = -a[2]; + return out; +} + +/** + * Returns the inverse of the components of a vec3 + * + * @param {vec3} out the receiving vector + * @param {vec3} a vector to invert + * @returns {vec3} out + */ +export function inverse(out, a) { + out[0] = 1.0 / a[0]; + out[1] = 1.0 / a[1]; + out[2] = 1.0 / a[2]; + return out; +} + +/** + * Normalize a vec3 + * + * @param {vec3} out the receiving vector + * @param {vec3} a vector to normalize + * @returns {vec3} out + */ +export function normalize(out, a) { + let x = a[0]; + let y = a[1]; + let z = a[2]; + let len = x*x + y*y + z*z; + if (len > 0) { + //TODO: evaluate use of glm_invsqrt here? + len = 1 / Math.sqrt(len); + out[0] = a[0] * len; + out[1] = a[1] * len; + out[2] = a[2] * len; + } + return out; +} + +/** + * Calculates the dot product of two vec3's + * + * @param {vec3} a the first operand + * @param {vec3} b the second operand + * @returns {Number} dot product of a and b + */ +export function dot(a, b) { + return a[0] * b[0] + a[1] * b[1] + a[2] * b[2]; +} + +/** + * Computes the cross product of two vec3's + * + * @param {vec3} out the receiving vector + * @param {vec3} a the first operand + * @param {vec3} b the second operand + * @returns {vec3} out + */ +export function cross(out, a, b) { + let ax = a[0], ay = a[1], az = a[2]; + let bx = b[0], by = b[1], bz = b[2]; + + out[0] = ay * bz - az * by; + out[1] = az * bx - ax * bz; + out[2] = ax * by - ay * bx; + return out; +} + +/** + * Performs a linear interpolation between two vec3's + * + * @param {vec3} out the receiving vector + * @param {vec3} a the first operand + * @param {vec3} b the second operand + * @param {Number} t interpolation amount between the two inputs + * @returns {vec3} out + */ +export function lerp(out, a, b, t) { + let ax = a[0]; + let ay = a[1]; + let az = a[2]; + out[0] = ax + t * (b[0] - ax); + out[1] = ay + t * (b[1] - ay); + out[2] = az + t * (b[2] - az); + return out; +} + +/** + * Performs a hermite interpolation with two control points + * + * @param {vec3} out the receiving vector + * @param {vec3} a the first operand + * @param {vec3} b the second operand + * @param {vec3} c the third operand + * @param {vec3} d the fourth operand + * @param {Number} t interpolation amount between the two inputs + * @returns {vec3} out + */ +export function hermite(out, a, b, c, d, t) { + let factorTimes2 = t * t; + let factor1 = factorTimes2 * (2 * t - 3) + 1; + let factor2 = factorTimes2 * (t - 2) + t; + let factor3 = factorTimes2 * (t - 1); + let factor4 = factorTimes2 * (3 - 2 * t); + + out[0] = a[0] * factor1 + b[0] * factor2 + c[0] * factor3 + d[0] * factor4; + out[1] = a[1] * factor1 + b[1] * factor2 + c[1] * factor3 + d[1] * factor4; + out[2] = a[2] * factor1 + b[2] * factor2 + c[2] * factor3 + d[2] * factor4; + + return out; +} + +/** + * Performs a bezier interpolation with two control points + * + * @param {vec3} out the receiving vector + * @param {vec3} a the first operand + * @param {vec3} b the second operand + * @param {vec3} c the third operand + * @param {vec3} d the fourth operand + * @param {Number} t interpolation amount between the two inputs + * @returns {vec3} out + */ +export function bezier(out, a, b, c, d, t) { + let inverseFactor = 1 - t; + let inverseFactorTimesTwo = inverseFactor * inverseFactor; + let factorTimes2 = t * t; + let factor1 = inverseFactorTimesTwo * inverseFactor; + let factor2 = 3 * t * inverseFactorTimesTwo; + let factor3 = 3 * factorTimes2 * inverseFactor; + let factor4 = factorTimes2 * t; + + out[0] = a[0] * factor1 + b[0] * factor2 + c[0] * factor3 + d[0] * factor4; + out[1] = a[1] * factor1 + b[1] * factor2 + c[1] * factor3 + d[1] * factor4; + out[2] = a[2] * factor1 + b[2] * factor2 + c[2] * factor3 + d[2] * factor4; + + return out; +} + +/** + * Generates a random vector with the given scale + * + * @param {vec3} out the receiving vector + * @param {Number} [scale] Length of the resulting vector. If ommitted, a unit vector will be returned + * @returns {vec3} out + */ +export function random(out, scale) { + scale = scale || 1.0; + + let r = glMatrix.RANDOM() * 2.0 * Math.PI; + let z = (glMatrix.RANDOM() * 2.0) - 1.0; + let zScale = Math.sqrt(1.0-z*z) * scale; + + out[0] = Math.cos(r) * zScale; + out[1] = Math.sin(r) * zScale; + out[2] = z * scale; + return out; +} + +/** + * Transforms the vec3 with a mat4. + * 4th vector component is implicitly '1' + * + * @param {vec3} out the receiving vector + * @param {vec3} a the vector to transform + * @param {mat4} m matrix to transform with + * @returns {vec3} out + */ +export function transformMat4(out, a, m) { + let x = a[0], y = a[1], z = a[2]; + let w = m[3] * x + m[7] * y + m[11] * z + m[15]; + w = w || 1.0; + out[0] = (m[0] * x + m[4] * y + m[8] * z + m[12]) / w; + out[1] = (m[1] * x + m[5] * y + m[9] * z + m[13]) / w; + out[2] = (m[2] * x + m[6] * y + m[10] * z + m[14]) / w; + return out; +} + +/** + * Transforms the vec3 with a mat3. + * + * @param {vec3} out the receiving vector + * @param {vec3} a the vector to transform + * @param {mat3} m the 3x3 matrix to transform with + * @returns {vec3} out + */ +export function transformMat3(out, a, m) { + let x = a[0], y = a[1], z = a[2]; + out[0] = x * m[0] + y * m[3] + z * m[6]; + out[1] = x * m[1] + y * m[4] + z * m[7]; + out[2] = x * m[2] + y * m[5] + z * m[8]; + return out; +} + +/** + * Transforms the vec3 with a quat + * + * @param {vec3} out the receiving vector + * @param {vec3} a the vector to transform + * @param {quat} q quaternion to transform with + * @returns {vec3} out + */ +export function transformQuat(out, a, q) { + // benchmarks: http://jsperf.com/quaternion-transform-vec3-implementations + + let x = a[0], y = a[1], z = a[2]; + let qx = q[0], qy = q[1], qz = q[2], qw = q[3]; + + // calculate quat * vec + let ix = qw * x + qy * z - qz * y; + let iy = qw * y + qz * x - qx * z; + let iz = qw * z + qx * y - qy * x; + let iw = -qx * x - qy * y - qz * z; + + // calculate result * inverse quat + out[0] = ix * qw + iw * -qx + iy * -qz - iz * -qy; + out[1] = iy * qw + iw * -qy + iz * -qx - ix * -qz; + out[2] = iz * qw + iw * -qz + ix * -qy - iy * -qx; + return out; +} + +/** + * Rotate a 3D vector around the x-axis + * @param {vec3} out The receiving vec3 + * @param {vec3} a The vec3 point to rotate + * @param {vec3} b The origin of the rotation + * @param {Number} c The angle of rotation + * @returns {vec3} out + */ +export function rotateX(out, a, b, c){ + let p = [], r=[]; + //Translate point to the origin + p[0] = a[0] - b[0]; + p[1] = a[1] - b[1]; + p[2] = a[2] - b[2]; + + //perform rotation + r[0] = p[0]; + r[1] = p[1]*Math.cos(c) - p[2]*Math.sin(c); + r[2] = p[1]*Math.sin(c) + p[2]*Math.cos(c); + + //translate to correct position + out[0] = r[0] + b[0]; + out[1] = r[1] + b[1]; + out[2] = r[2] + b[2]; + + return out; +} + +/** + * Rotate a 3D vector around the y-axis + * @param {vec3} out The receiving vec3 + * @param {vec3} a The vec3 point to rotate + * @param {vec3} b The origin of the rotation + * @param {Number} c The angle of rotation + * @returns {vec3} out + */ +export function rotateY(out, a, b, c){ + let p = [], r=[]; + //Translate point to the origin + p[0] = a[0] - b[0]; + p[1] = a[1] - b[1]; + p[2] = a[2] - b[2]; + + //perform rotation + r[0] = p[2]*Math.sin(c) + p[0]*Math.cos(c); + r[1] = p[1]; + r[2] = p[2]*Math.cos(c) - p[0]*Math.sin(c); + + //translate to correct position + out[0] = r[0] + b[0]; + out[1] = r[1] + b[1]; + out[2] = r[2] + b[2]; + + return out; +} + +/** + * Rotate a 3D vector around the z-axis + * @param {vec3} out The receiving vec3 + * @param {vec3} a The vec3 point to rotate + * @param {vec3} b The origin of the rotation + * @param {Number} c The angle of rotation + * @returns {vec3} out + */ +export function rotateZ(out, a, b, c){ + let p = [], r=[]; + //Translate point to the origin + p[0] = a[0] - b[0]; + p[1] = a[1] - b[1]; + p[2] = a[2] - b[2]; + + //perform rotation + r[0] = p[0]*Math.cos(c) - p[1]*Math.sin(c); + r[1] = p[0]*Math.sin(c) + p[1]*Math.cos(c); + r[2] = p[2]; + + //translate to correct position + out[0] = r[0] + b[0]; + out[1] = r[1] + b[1]; + out[2] = r[2] + b[2]; + + return out; +} + +/** + * Get the angle between two 3D vectors + * @param {vec3} a The first operand + * @param {vec3} b The second operand + * @returns {Number} The angle in radians + */ +export function angle(a, b) { + let tempA = fromValues(a[0], a[1], a[2]); + let tempB = fromValues(b[0], b[1], b[2]); + + normalize(tempA, tempA); + normalize(tempB, tempB); + + let cosine = dot(tempA, tempB); + + if(cosine > 1.0) { + return 0; + } + else if(cosine < -1.0) { + return Math.PI; + } else { + return Math.acos(cosine); + } +} + +/** + * Returns a string representation of a vector + * + * @param {vec3} a vector to represent as a string + * @returns {String} string representation of the vector + */ +export function str(a) { + return 'vec3(' + a[0] + ', ' + a[1] + ', ' + a[2] + ')'; +} + +/** + * Returns whether or not the vectors have exactly the same elements in the same position (when compared with ===) + * + * @param {vec3} a The first vector. + * @param {vec3} b The second vector. + * @returns {Boolean} True if the vectors are equal, false otherwise. + */ +export function exactEquals(a, b) { + return a[0] === b[0] && a[1] === b[1] && a[2] === b[2]; +} + +/** + * Returns whether or not the vectors have approximately the same elements in the same position. + * + * @param {vec3} a The first vector. + * @param {vec3} b The second vector. + * @returns {Boolean} True if the vectors are equal, false otherwise. + */ +export function equals(a, b) { + let a0 = a[0], a1 = a[1], a2 = a[2]; + let b0 = b[0], b1 = b[1], b2 = b[2]; + return (Math.abs(a0 - b0) <= glMatrix.EPSILON*Math.max(1.0, Math.abs(a0), Math.abs(b0)) && + Math.abs(a1 - b1) <= glMatrix.EPSILON*Math.max(1.0, Math.abs(a1), Math.abs(b1)) && + Math.abs(a2 - b2) <= glMatrix.EPSILON*Math.max(1.0, Math.abs(a2), Math.abs(b2))); +} + +/** + * Alias for {@link vec3.subtract} + * @function + */ +export const sub = subtract; + +/** + * Alias for {@link vec3.multiply} + * @function + */ +export const mul = multiply; + +/** + * Alias for {@link vec3.divide} + * @function + */ +export const div = divide; + +/** + * Alias for {@link vec3.distance} + * @function + */ +export const dist = distance; + +/** + * Alias for {@link vec3.squaredDistance} + * @function + */ +export const sqrDist = squaredDistance; + +/** + * Alias for {@link vec3.length} + * @function + */ +export const len = length; + +/** + * Alias for {@link vec3.squaredLength} + * @function + */ +export const sqrLen = squaredLength; + +/** + * Perform some operation over an array of vec3s. + * + * @param {Array} a the array of vectors to iterate over + * @param {Number} stride Number of elements between the start of each vec3. If 0 assumes tightly packed + * @param {Number} offset Number of elements to skip at the beginning of the array + * @param {Number} count Number of vec3s to iterate over. If 0 iterates over entire array + * @param {Function} fn Function to call for each vector in the array + * @param {Object} [arg] additional argument to pass to fn + * @returns {Array} a + * @function + */ +export const forEach = (function() { + let vec = create(); + + return function(a, stride, offset, count, fn, arg) { + let i, l; + if(!stride) { + stride = 3; + } + + if(!offset) { + offset = 0; + } + + if(count) { + l = Math.min((count * stride) + offset, a.length); + } else { + l = a.length; + } + + for(i = offset; i < l; i += stride) { + vec[0] = a[i]; vec[1] = a[i+1]; vec[2] = a[i+2]; + fn(vec, vec, arg); + a[i] = vec[0]; a[i+1] = vec[1]; a[i+2] = vec[2]; + } + + return a; + }; +})(); diff --git a/src/globe/beam/glMatrix/vec4.js b/src/globe/beam/glMatrix/vec4.js new file mode 100755 index 0000000..b693682 --- /dev/null +++ b/src/globe/beam/glMatrix/vec4.js @@ -0,0 +1,606 @@ +/* Copyright (c) 2015, Brandon Jones, Colin MacKenzie IV. + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. */ + +import * as glMatrix from "./common"; + +/** + * 4 Dimensional Vector + * @module vec4 + */ + +/** + * Creates a new, empty vec4 + * + * @returns {vec4} a new 4D vector + */ +export function create() { + let out = new glMatrix.ARRAY_TYPE(4); + out[0] = 0; + out[1] = 0; + out[2] = 0; + out[3] = 0; + return out; +} + +/** + * Creates a new vec4 initialized with values from an existing vector + * + * @param {vec4} a vector to clone + * @returns {vec4} a new 4D vector + */ +export function clone(a) { + let out = new glMatrix.ARRAY_TYPE(4); + out[0] = a[0]; + out[1] = a[1]; + out[2] = a[2]; + out[3] = a[3]; + return out; +} + +/** + * Creates a new vec4 initialized with the given values + * + * @param {Number} x X component + * @param {Number} y Y component + * @param {Number} z Z component + * @param {Number} w W component + * @returns {vec4} a new 4D vector + */ +export function fromValues(x, y, z, w) { + let out = new glMatrix.ARRAY_TYPE(4); + out[0] = x; + out[1] = y; + out[2] = z; + out[3] = w; + return out; +} + +/** + * Copy the values from one vec4 to another + * + * @param {vec4} out the receiving vector + * @param {vec4} a the source vector + * @returns {vec4} out + */ +export function copy(out, a) { + out[0] = a[0]; + out[1] = a[1]; + out[2] = a[2]; + out[3] = a[3]; + return out; +} + +/** + * Set the components of a vec4 to the given values + * + * @param {vec4} out the receiving vector + * @param {Number} x X component + * @param {Number} y Y component + * @param {Number} z Z component + * @param {Number} w W component + * @returns {vec4} out + */ +export function set(out, x, y, z, w) { + out[0] = x; + out[1] = y; + out[2] = z; + out[3] = w; + return out; +} + +/** + * Adds two vec4's + * + * @param {vec4} out the receiving vector + * @param {vec4} a the first operand + * @param {vec4} b the second operand + * @returns {vec4} out + */ +export function add(out, a, b) { + out[0] = a[0] + b[0]; + out[1] = a[1] + b[1]; + out[2] = a[2] + b[2]; + out[3] = a[3] + b[3]; + return out; +} + +/** + * Subtracts vector b from vector a + * + * @param {vec4} out the receiving vector + * @param {vec4} a the first operand + * @param {vec4} b the second operand + * @returns {vec4} out + */ +export function subtract(out, a, b) { + out[0] = a[0] - b[0]; + out[1] = a[1] - b[1]; + out[2] = a[2] - b[2]; + out[3] = a[3] - b[3]; + return out; +} + +/** + * Multiplies two vec4's + * + * @param {vec4} out the receiving vector + * @param {vec4} a the first operand + * @param {vec4} b the second operand + * @returns {vec4} out + */ +export function multiply(out, a, b) { + out[0] = a[0] * b[0]; + out[1] = a[1] * b[1]; + out[2] = a[2] * b[2]; + out[3] = a[3] * b[3]; + return out; +} + +/** + * Divides two vec4's + * + * @param {vec4} out the receiving vector + * @param {vec4} a the first operand + * @param {vec4} b the second operand + * @returns {vec4} out + */ +export function divide(out, a, b) { + out[0] = a[0] / b[0]; + out[1] = a[1] / b[1]; + out[2] = a[2] / b[2]; + out[3] = a[3] / b[3]; + return out; +} + +/** + * Math.ceil the components of a vec4 + * + * @param {vec4} out the receiving vector + * @param {vec4} a vector to ceil + * @returns {vec4} out + */ +export function ceil(out, a) { + out[0] = Math.ceil(a[0]); + out[1] = Math.ceil(a[1]); + out[2] = Math.ceil(a[2]); + out[3] = Math.ceil(a[3]); + return out; +} + +/** + * Math.floor the components of a vec4 + * + * @param {vec4} out the receiving vector + * @param {vec4} a vector to floor + * @returns {vec4} out + */ +export function floor(out, a) { + out[0] = Math.floor(a[0]); + out[1] = Math.floor(a[1]); + out[2] = Math.floor(a[2]); + out[3] = Math.floor(a[3]); + return out; +} + +/** + * Returns the minimum of two vec4's + * + * @param {vec4} out the receiving vector + * @param {vec4} a the first operand + * @param {vec4} b the second operand + * @returns {vec4} out + */ +export function min(out, a, b) { + out[0] = Math.min(a[0], b[0]); + out[1] = Math.min(a[1], b[1]); + out[2] = Math.min(a[2], b[2]); + out[3] = Math.min(a[3], b[3]); + return out; +} + +/** + * Returns the maximum of two vec4's + * + * @param {vec4} out the receiving vector + * @param {vec4} a the first operand + * @param {vec4} b the second operand + * @returns {vec4} out + */ +export function max(out, a, b) { + out[0] = Math.max(a[0], b[0]); + out[1] = Math.max(a[1], b[1]); + out[2] = Math.max(a[2], b[2]); + out[3] = Math.max(a[3], b[3]); + return out; +} + +/** + * Math.round the components of a vec4 + * + * @param {vec4} out the receiving vector + * @param {vec4} a vector to round + * @returns {vec4} out + */ +export function round(out, a) { + out[0] = Math.round(a[0]); + out[1] = Math.round(a[1]); + out[2] = Math.round(a[2]); + out[3] = Math.round(a[3]); + return out; +} + +/** + * Scales a vec4 by a scalar number + * + * @param {vec4} out the receiving vector + * @param {vec4} a the vector to scale + * @param {Number} b amount to scale the vector by + * @returns {vec4} out + */ +export function scale(out, a, b) { + out[0] = a[0] * b; + out[1] = a[1] * b; + out[2] = a[2] * b; + out[3] = a[3] * b; + return out; +} + +/** + * Adds two vec4's after scaling the second operand by a scalar value + * + * @param {vec4} out the receiving vector + * @param {vec4} a the first operand + * @param {vec4} b the second operand + * @param {Number} scale the amount to scale b by before adding + * @returns {vec4} out + */ +export function scaleAndAdd(out, a, b, scale) { + out[0] = a[0] + (b[0] * scale); + out[1] = a[1] + (b[1] * scale); + out[2] = a[2] + (b[2] * scale); + out[3] = a[3] + (b[3] * scale); + return out; +} + +/** + * Calculates the euclidian distance between two vec4's + * + * @param {vec4} a the first operand + * @param {vec4} b the second operand + * @returns {Number} distance between a and b + */ +export function distance(a, b) { + let x = b[0] - a[0]; + let y = b[1] - a[1]; + let z = b[2] - a[2]; + let w = b[3] - a[3]; + return Math.sqrt(x*x + y*y + z*z + w*w); +} + +/** + * Calculates the squared euclidian distance between two vec4's + * + * @param {vec4} a the first operand + * @param {vec4} b the second operand + * @returns {Number} squared distance between a and b + */ +export function squaredDistance(a, b) { + let x = b[0] - a[0]; + let y = b[1] - a[1]; + let z = b[2] - a[2]; + let w = b[3] - a[3]; + return x*x + y*y + z*z + w*w; +} + +/** + * Calculates the length of a vec4 + * + * @param {vec4} a vector to calculate length of + * @returns {Number} length of a + */ +export function length(a) { + let x = a[0]; + let y = a[1]; + let z = a[2]; + let w = a[3]; + return Math.sqrt(x*x + y*y + z*z + w*w); +} + +/** + * Calculates the squared length of a vec4 + * + * @param {vec4} a vector to calculate squared length of + * @returns {Number} squared length of a + */ +export function squaredLength(a) { + let x = a[0]; + let y = a[1]; + let z = a[2]; + let w = a[3]; + return x*x + y*y + z*z + w*w; +} + +/** + * Negates the components of a vec4 + * + * @param {vec4} out the receiving vector + * @param {vec4} a vector to negate + * @returns {vec4} out + */ +export function negate(out, a) { + out[0] = -a[0]; + out[1] = -a[1]; + out[2] = -a[2]; + out[3] = -a[3]; + return out; +} + +/** + * Returns the inverse of the components of a vec4 + * + * @param {vec4} out the receiving vector + * @param {vec4} a vector to invert + * @returns {vec4} out + */ +export function inverse(out, a) { + out[0] = 1.0 / a[0]; + out[1] = 1.0 / a[1]; + out[2] = 1.0 / a[2]; + out[3] = 1.0 / a[3]; + return out; +} + +/** + * Normalize a vec4 + * + * @param {vec4} out the receiving vector + * @param {vec4} a vector to normalize + * @returns {vec4} out + */ +export function normalize(out, a) { + let x = a[0]; + let y = a[1]; + let z = a[2]; + let w = a[3]; + let len = x*x + y*y + z*z + w*w; + if (len > 0) { + len = 1 / Math.sqrt(len); + out[0] = x * len; + out[1] = y * len; + out[2] = z * len; + out[3] = w * len; + } + return out; +} + +/** + * Calculates the dot product of two vec4's + * + * @param {vec4} a the first operand + * @param {vec4} b the second operand + * @returns {Number} dot product of a and b + */ +export function dot(a, b) { + return a[0] * b[0] + a[1] * b[1] + a[2] * b[2] + a[3] * b[3]; +} + +/** + * Performs a linear interpolation between two vec4's + * + * @param {vec4} out the receiving vector + * @param {vec4} a the first operand + * @param {vec4} b the second operand + * @param {Number} t interpolation amount between the two inputs + * @returns {vec4} out + */ +export function lerp(out, a, b, t) { + let ax = a[0]; + let ay = a[1]; + let az = a[2]; + let aw = a[3]; + out[0] = ax + t * (b[0] - ax); + out[1] = ay + t * (b[1] - ay); + out[2] = az + t * (b[2] - az); + out[3] = aw + t * (b[3] - aw); + return out; +} + +/** + * Generates a random vector with the given scale + * + * @param {vec4} out the receiving vector + * @param {Number} [scale] Length of the resulting vector. If ommitted, a unit vector will be returned + * @returns {vec4} out + */ +export function random(out, vectorScale) { + vectorScale = vectorScale || 1.0; + + //TODO: This is a pretty awful way of doing this. Find something better. + out[0] = glMatrix.RANDOM(); + out[1] = glMatrix.RANDOM(); + out[2] = glMatrix.RANDOM(); + out[3] = glMatrix.RANDOM(); + normalize(out, out); + scale(out, out, vectorScale); + return out; +} + +/** + * Transforms the vec4 with a mat4. + * + * @param {vec4} out the receiving vector + * @param {vec4} a the vector to transform + * @param {mat4} m matrix to transform with + * @returns {vec4} out + */ +export function transformMat4(out, a, m) { + let x = a[0], y = a[1], z = a[2], w = a[3]; + out[0] = m[0] * x + m[4] * y + m[8] * z + m[12] * w; + out[1] = m[1] * x + m[5] * y + m[9] * z + m[13] * w; + out[2] = m[2] * x + m[6] * y + m[10] * z + m[14] * w; + out[3] = m[3] * x + m[7] * y + m[11] * z + m[15] * w; + return out; +} + +/** + * Transforms the vec4 with a quat + * + * @param {vec4} out the receiving vector + * @param {vec4} a the vector to transform + * @param {quat} q quaternion to transform with + * @returns {vec4} out + */ +export function transformQuat(out, a, q) { + let x = a[0], y = a[1], z = a[2]; + let qx = q[0], qy = q[1], qz = q[2], qw = q[3]; + + // calculate quat * vec + let ix = qw * x + qy * z - qz * y; + let iy = qw * y + qz * x - qx * z; + let iz = qw * z + qx * y - qy * x; + let iw = -qx * x - qy * y - qz * z; + + // calculate result * inverse quat + out[0] = ix * qw + iw * -qx + iy * -qz - iz * -qy; + out[1] = iy * qw + iw * -qy + iz * -qx - ix * -qz; + out[2] = iz * qw + iw * -qz + ix * -qy - iy * -qx; + out[3] = a[3]; + return out; +} + +/** + * Returns a string representation of a vector + * + * @param {vec4} a vector to represent as a string + * @returns {String} string representation of the vector + */ +export function str(a) { + return 'vec4(' + a[0] + ', ' + a[1] + ', ' + a[2] + ', ' + a[3] + ')'; +} + +/** + * Returns whether or not the vectors have exactly the same elements in the same position (when compared with ===) + * + * @param {vec4} a The first vector. + * @param {vec4} b The second vector. + * @returns {Boolean} True if the vectors are equal, false otherwise. + */ +export function exactEquals(a, b) { + return a[0] === b[0] && a[1] === b[1] && a[2] === b[2] && a[3] === b[3]; +} + +/** + * Returns whether or not the vectors have approximately the same elements in the same position. + * + * @param {vec4} a The first vector. + * @param {vec4} b The second vector. + * @returns {Boolean} True if the vectors are equal, false otherwise. + */ +export function equals(a, b) { + let a0 = a[0], a1 = a[1], a2 = a[2], a3 = a[3]; + let b0 = b[0], b1 = b[1], b2 = b[2], b3 = b[3]; + return (Math.abs(a0 - b0) <= glMatrix.EPSILON*Math.max(1.0, Math.abs(a0), Math.abs(b0)) && + Math.abs(a1 - b1) <= glMatrix.EPSILON*Math.max(1.0, Math.abs(a1), Math.abs(b1)) && + Math.abs(a2 - b2) <= glMatrix.EPSILON*Math.max(1.0, Math.abs(a2), Math.abs(b2)) && + Math.abs(a3 - b3) <= glMatrix.EPSILON*Math.max(1.0, Math.abs(a3), Math.abs(b3))); +} + +/** + * Alias for {@link vec4.subtract} + * @function + */ +export const sub = subtract; + +/** + * Alias for {@link vec4.multiply} + * @function + */ +export const mul = multiply; + +/** + * Alias for {@link vec4.divide} + * @function + */ +export const div = divide; + +/** + * Alias for {@link vec4.distance} + * @function + */ +export const dist = distance; + +/** + * Alias for {@link vec4.squaredDistance} + * @function + */ +export const sqrDist = squaredDistance; + +/** + * Alias for {@link vec4.length} + * @function + */ +export const len = length; + +/** + * Alias for {@link vec4.squaredLength} + * @function + */ +export const sqrLen = squaredLength; + +/** + * Perform some operation over an array of vec4s. + * + * @param {Array} a the array of vectors to iterate over + * @param {Number} stride Number of elements between the start of each vec4. If 0 assumes tightly packed + * @param {Number} offset Number of elements to skip at the beginning of the array + * @param {Number} count Number of vec4s to iterate over. If 0 iterates over entire array + * @param {Function} fn Function to call for each vector in the array + * @param {Object} [arg] additional argument to pass to fn + * @returns {Array} a + * @function + */ +export const forEach = (function() { + let vec = create(); + + return function(a, stride, offset, count, fn, arg) { + let i, l; + if(!stride) { + stride = 4; + } + + if(!offset) { + offset = 0; + } + + if(count) { + l = Math.min((count * stride) + offset, a.length); + } else { + l = a.length; + } + + for(i = offset; i < l; i += stride) { + vec[0] = a[i]; vec[1] = a[i+1]; vec[2] = a[i+2]; vec[3] = a[i+3]; + fn(vec, vec, arg); + a[i] = vec[0]; a[i+1] = vec[1]; a[i+2] = vec[2]; a[i+3] = vec[3]; + } + + return a; + }; +})(); diff --git a/src/globe/beam/index.js b/src/globe/beam/index.js new file mode 100755 index 0000000..42770ba --- /dev/null +++ b/src/globe/beam/index.js @@ -0,0 +1,27 @@ +export {default as ArrayBuffer} from './ArrayBuffer'; +export {default as Program} from './Program'; +export {default as Material} from './Material'; +export {default as Texture} from './Texture'; +export {default as Container} from './Container'; +export {default as Mesh} from './Mesh'; +export {default as Renderer} from './Renderer'; +export {default as Camera} from './Camera'; +export {default as Object3d} from './Object3d'; + +import * as mat2 from "./glMatrix/mat2"; +import * as mat2d from "./glMatrix/mat2d"; +import * as mat3 from "./glMatrix/mat3"; +import * as mat4 from "./glMatrix/mat4"; +import * as quat from "./glMatrix/quat"; +import * as vec2 from "./glMatrix/vec2"; +import * as vec3 from "./glMatrix/vec3"; +import * as vec4 from "./glMatrix/vec4"; +export { + mat2, mat2d, mat3, mat4, + quat, + vec2, vec3, vec4, +}; + +export {default as GeometryBuffer} from './GeometryBuffer'; +export {default as PlaneGeometryBuffer} from './PlaneGeometryBuffer'; +export {default as SphereGeometryBuffer} from './SphereGeometryBuffer'; \ No newline at end of file diff --git a/src/globe/beam/shaders/default-fs.glsl b/src/globe/beam/shaders/default-fs.glsl new file mode 100755 index 0000000..0644e4e --- /dev/null +++ b/src/globe/beam/shaders/default-fs.glsl @@ -0,0 +1,8 @@ +precision highp float; + +uniform float alpha; +varying vec2 vUv; + +void main(void) { + gl_FragColor = vec4( vec3(1., 1., 1.), alpha); +} \ No newline at end of file diff --git a/src/globe/beam/shaders/default-vs.glsl b/src/globe/beam/shaders/default-vs.glsl new file mode 100755 index 0000000..2beb6fb --- /dev/null +++ b/src/globe/beam/shaders/default-vs.glsl @@ -0,0 +1,14 @@ +precision highp float; + +attribute vec2 uv; +attribute vec3 position; + +uniform mat4 uMVMatrix; +uniform mat4 uPMatrix; + +varying vec2 vUv; + +void main(void) { + vUv = uv; + gl_Position = uPMatrix * uMVMatrix * vec4(position, 1.0); +} \ No newline at end of file diff --git a/src/globe/beam/shaders/mesh-fs.glsl b/src/globe/beam/shaders/mesh-fs.glsl new file mode 100755 index 0000000..cbaeaba --- /dev/null +++ b/src/globe/beam/shaders/mesh-fs.glsl @@ -0,0 +1,33 @@ +precision highp float; + +uniform float alpha; +varying vec3 vColor; +varying vec2 vUv; + +uniform vec2 offset; + +#ifdef USE_MAP + uniform sampler2D map; + uniform vec2 mapOffset; +#endif + +#ifdef USE_ALPHA_MAP + uniform sampler2D alphaMap; + uniform vec2 alphaMapOffset; +#endif + + +uniform vec3 color; + +void main(void) { + + vec4 color = vec4(color, alpha); + + #ifdef USE_MAP + color = texture2D(map, vUv + offset); + color.a *= alpha; + #endif + + gl_FragColor = color; + +} \ No newline at end of file diff --git a/src/globe/beam/shaders/particle-fs.glsl b/src/globe/beam/shaders/particle-fs.glsl new file mode 100755 index 0000000..be63741 --- /dev/null +++ b/src/globe/beam/shaders/particle-fs.glsl @@ -0,0 +1,11 @@ +precision highp float; + + +varying vec2 vUv; + +void main(void) { + + vec4 outColor = vec4(1., 0., 0., 1.0); + gl_FragColor = outColor; + +} \ No newline at end of file diff --git a/src/globe/beam/shaders/particle-position-fs.glsl b/src/globe/beam/shaders/particle-position-fs.glsl new file mode 100755 index 0000000..ab1a83a --- /dev/null +++ b/src/globe/beam/shaders/particle-position-fs.glsl @@ -0,0 +1,62 @@ +// simulation +varying vec2 vUv; + +uniform sampler2D tPositions; +uniform sampler2D tOrigin; +uniform sampler2D tTarget; +uniform sampler2D tVelocity; + +uniform float timer; + +uniform float targetSpeed; + +uniform vec3 meshPosition; + + + +uniform float width; +uniform float height; +uniform float depth; + +void main() { + + vec3 pos = texture2D( tPositions, vUv ).xyz; + vec3 velocity = texture2D( tVelocity, vUv ).xyz; + vec3 target = texture2D( tTarget, vUv ).xyz; + + pos += velocity; + + // if (target.x == 0. + // && target.y == 0. + // && target.z == 0. ) { + // //no target sepcified + // } + // else{ + // pos.x += (target.x - pos.x) * targetSpeed; + // pos.y += (target.y - pos.y) * targetSpeed; + // pos.z += (target.z - pos.z) * targetSpeed; + // } + + //pos.z += meshPosition.z; + + //GROUND + // if (pos.y < 0.0) { + // pos.y = 0.0; + // } + + if( pos.y > height * .5) { + pos.y = height * -.5 + 1.; + } + if (pos.y < height * -.5) { + pos.y = height * .5 - 1.; + } + if (pos.x > width * .5) { + pos.x = width * -.5; + } + if (pos.x < width * -.5) { + pos.x = width * .5; + } + + gl_FragColor = vec4(pos, 1.0); + +} \ No newline at end of file diff --git a/src/globe/beam/shaders/particle-velocity-fs.glsl b/src/globe/beam/shaders/particle-velocity-fs.glsl new file mode 100755 index 0000000..2bb718c --- /dev/null +++ b/src/globe/beam/shaders/particle-velocity-fs.glsl @@ -0,0 +1,135 @@ +// simulation +varying vec2 vUv; + +uniform sampler2D tPositions; +uniform sampler2D tOrigin; +uniform sampler2D tTarget; +uniform sampler2D tVelocity; +uniform sampler2D tForce; + +uniform float timer; +uniform vec3 collisionMouse; +uniform float forceTarget; +uniform float delta; + +uniform int useMouse; + +#define M_PI 3.1415926535897932384626433832795 + +uniform float gravityStrength; +uniform float windStrength; +uniform float targetStrength; + +void main() { + + float damping = 1.0 - 0.006; + float attractionForce = -10000000.0; + float attractionRadius = 5000.0; + + vec3 pos = texture2D( tPositions, vUv ).xyz * 1.0 - 0.5; + vec3 velocity = texture2D( tVelocity, vUv ).xyz* 1.0 - 0.5; + + // // //??? + // // velocity *= 0.5; + + vec3 force = vec3(0.0); + + // target + vec3 target = texture2D( tTarget, vUv ).xyz; + + if (target.x != 0. + && target.y != 0. + && target.z != 0. ) { + + float targetDx = pos.x - target.x; + float targetDy = pos.y - target.y; + float targetDz = pos.z - target.z; + + float targetRadiusSq = 10.0 * 10.0; + + float targetDistSq = (targetDx*targetDx + targetDy*targetDy + targetDz*targetDz); + + if (targetDistSq > 0.1) {//avoid shake + vec3 attractionTarget = vec3( target.x, target.y, target.z ); + attractionTarget -= pos; + attractionTarget = normalize( attractionTarget ); + attractionTarget *= targetDistSq * targetStrength; + + force += attractionTarget; + } + } + + + /** + * COMPUTE FORCE + */ + // if (useMouse == 1) { + // float dx = pos.x - collisionMouse.x; + // float dy = pos.y - collisionMouse.y; + // float dz = pos.z - collisionMouse.z; + + // float distSq = (dx*dx + dy*dy + dz*dz); + // float attractionRadiusSq = attractionRadius*attractionRadius; + + // if (distSq > 0.000004 && distSq < attractionRadiusSq) { + + // float ratio = (1.0 - distSq / attractionRadiusSq); //dist / attractionRadius; + + // vec3 attractionBehaviourForce = vec3( collisionMouse.x, collisionMouse.y, collisionMouse.z ); + + // attractionBehaviourForce -= pos; + + // attractionBehaviourForce = normalize( attractionBehaviourForce ); + + // attractionBehaviourForce *= ratio; + // attractionBehaviourForce *= attractionForce; + + // force += attractionBehaviourForce; + + // } + // } + + + //GRAVITY + vec3 gravityForce = vec3(0., -1., 0.); + gravityForce *= gravityStrength; + force += gravityForce; + + //wind + vec3 windForce = vec3(1., 0., 0.); + windForce *= windStrength; + force += windForce; + + + + /** + * COMPUTE VELOCITY [EULER INTEGRATE] + */ + + vec3 oldVelocity = vec3( velocity.x, velocity.y, velocity.z ); + + vec3 newForce = force * timer; + vec3 newVelocity = velocity + newForce; + + newVelocity *= damping; + + oldVelocity += newVelocity; + oldVelocity *= 0.5 * timer; + + + // particle.old.p.copy(particle.p); + // particle.old.v.copy(particle.v); + + // particle.a.multiplyScalar(1 / particle.mass); + // particle.v.add(particle.a.multiplyScalar(time)); + // particle.p.add(particle.old.v.multiplyScalar(time)); + // if (damping){ + // particle.v.multiplyScalar(damping); + // } + // particle.a.clear(); + + + + gl_FragColor = vec4( oldVelocity, 1.0 ); + +} diff --git a/src/globe/beam/shaders/particle-vs.glsl b/src/globe/beam/shaders/particle-vs.glsl new file mode 100755 index 0000000..549fe32 --- /dev/null +++ b/src/globe/beam/shaders/particle-vs.glsl @@ -0,0 +1,38 @@ + +attribute vec2 uv; +attribute vec3 color; +attribute vec3 position; +attribute float vertexIndex; +attribute float particleIndex; + + +uniform mat4 uMVMatrix; +uniform mat4 uPMatrix; +// uniform float pointSize; + +varying vec2 vUv; + +void main() { + + vUv = uv; + + vec3 newPosition = position; + + if (vertexIndex == 0.0) { + newPosition += vec3(-1.,1.,0.); + } + else if (vertexIndex == 1.0) { + newPosition += vec3(1.,1.,0.); + } + else if (vertexIndex == 2.0) { + newPosition += vec3(-1.,-1.,0.); + } + else if (vertexIndex == 3.0) { + newPosition += vec3(1.,-1.,0.); + } + + newPosition *= 10.; + + gl_Position = uPMatrix * uMVMatrix * vec4( newPosition, 1.0 ); + +} \ No newline at end of file diff --git a/src/globe/beam/uniformTypes.js b/src/globe/beam/uniformTypes.js new file mode 100755 index 0000000..cb1bcfd --- /dev/null +++ b/src/globe/beam/uniformTypes.js @@ -0,0 +1,20 @@ +const UNIFORM_TYPES = {} +UNIFORM_TYPES[ 5126 /*FLOAT */ ] = '1f'; +UNIFORM_TYPES[ 35664 /*FLOAT_VEC2 */ ] = '2f'; +UNIFORM_TYPES[ 35665 /*FLOAT_VEC3 */ ] = '3f'; +UNIFORM_TYPES[ 35666 /*FLOAT_VEC4 */ ] = '4f'; +UNIFORM_TYPES[ 35670 /*BOOL */ ] = +UNIFORM_TYPES[ 5124 /*INT */ ] = +UNIFORM_TYPES[ 35678 /*SAMPLER_2D */ ] = +UNIFORM_TYPES[ 35680 /*SAMPLER_CUBE*/ ] = '1i'; +UNIFORM_TYPES[ 35671 /*BOOL_VEC2 */ ] = +UNIFORM_TYPES[ 35667 /*INT_VEC2 */ ] = '2i'; +UNIFORM_TYPES[ 35672 /*BOOL_VEC3 */ ] = +UNIFORM_TYPES[ 35668 /*INT_VEC3 */ ] = '3i'; +UNIFORM_TYPES[ 35673 /*BOOL_VEC4 */ ] = +UNIFORM_TYPES[ 35669 /*INT_VEC4 */ ] = '4i'; +UNIFORM_TYPES[ 35674 /*FLOAT_MAT2 */ ] = 'Matrix2f'; +UNIFORM_TYPES[ 35675 /*FLOAT_MAT3 */ ] = 'Matrix3f'; +UNIFORM_TYPES[ 35676 /*FLOAT_MAT4 */ ] = 'Matrix4f'; + +export default UNIFORM_TYPES; \ No newline at end of file diff --git a/src/globe/beam/utils/getFilter.js b/src/globe/beam/utils/getFilter.js new file mode 100755 index 0000000..609b8bc --- /dev/null +++ b/src/globe/beam/utils/getFilter.js @@ -0,0 +1,12 @@ +/* + * compute filtering enum, return one of the following : + * NEAREST + * LINEAR + * NEAREST_MIPMAP_NEAREST + * LINEAR_MIPMAP_NEAREST + * NEAREST_MIPMAP_LINEAR + * LINEAR_MIPMAP_LINEAR + */ +export default function getFilter( smooth, mipmap, miplinear ){ + return 0x2600 | (+smooth) | (+mipmap<<8) | ( +( mipmap && miplinear )<<1 ); +} \ No newline at end of file diff --git a/src/globe/beam/utils/isPowerOf2.js b/src/globe/beam/utils/isPowerOf2.js new file mode 100755 index 0000000..35f7712 --- /dev/null +++ b/src/globe/beam/utils/isPowerOf2.js @@ -0,0 +1,5 @@ + + +export default function isPowerOf2(value) { + return (value & (value - 1)) == 0; +} \ No newline at end of file diff --git a/src/globe/beam/utils/uuid.js b/src/globe/beam/utils/uuid.js new file mode 100755 index 0000000..70b62bc --- /dev/null +++ b/src/globe/beam/utils/uuid.js @@ -0,0 +1,31 @@ +// http://www.broofa.com/Tools/Math.uuid.htm +var chars = '0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz'.split( '' ); +var uuid = new Array( 36 ); +var rnd = 0, r; + +export default function generateUUID() { + + for ( var i = 0; i < 36; i ++ ) { + + if ( i === 8 || i === 13 || i === 18 || i === 23 ) { + + uuid[ i ] = '-'; + + } else if ( i === 14 ) { + + uuid[ i ] = '4'; + + } else { + + if ( rnd <= 0x02 ) rnd = 0x2000000 + ( Math.random() * 0x1000000 ) | 0; + r = rnd & 0xf; + rnd = rnd >> 4; + uuid[ i ] = chars[ ( i === 19 ) ? ( r & 0x3 ) | 0x8 : r ]; + + } + + } + + return uuid.join( '' ); + +}; \ No newline at end of file diff --git a/src/globe/beam/utils/warn.js b/src/globe/beam/utils/warn.js new file mode 100755 index 0000000..1aa2716 --- /dev/null +++ b/src/globe/beam/utils/warn.js @@ -0,0 +1,3 @@ +export default function warn(msg, ctx){ + console.log("%c" + "[warn]: " + msg, "color:#ff0084", ctx ); +} \ No newline at end of file diff --git a/src/globe/beam/webgl-obj-loader.js b/src/globe/beam/webgl-obj-loader.js new file mode 100755 index 0000000..8718791 --- /dev/null +++ b/src/globe/beam/webgl-obj-loader.js @@ -0,0 +1,396 @@ +/* +Copyright (c) 2013 Aaron Boman and aaronboman.com +Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: +The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +*/ +'use strict'; + +var OBJ = {}; + +/** + * The main Mesh class. The constructor will parse through the OBJ file data + * and collect the vertex, vertex normal, texture, and face information. This + * information can then be used later on when creating your VBOs. See + * OBJ.initMeshBuffers for an example of how to use the newly created Mesh + * + * @class Mesh + * @constructor + * + * @param {String} objectData a string representation of an OBJ file with newlines preserved. + */ +OBJ.Mesh = function (objectData) { + + + /* + The OBJ file format does a sort of compression when saving a model in a + program like Blender. There are at least 3 sections (4 including textures) + within the file. Each line in a section begins with the same string: + * 'v': indicates vertex section + * 'vn': indicates vertex normal section + * 'f': indicates the faces section + * 'vt': indicates vertex texture section (if textures were used on the model) + Each of the above sections (except for the faces section) is a list/set of + unique vertices. + + Each line of the faces section contains a list of + (vertex, [texture], normal) groups + Some examples: + // the texture index is optional, both formats are possible for models + // without a texture applied + f 1/25 18/46 12/31 + f 1//25 18//46 12//31 + + // A 3 vertex face with texture indices + f 16/92/11 14/101/22 1/69/1 + + // A 4 vertex face + f 16/92/11 40/109/40 38/114/38 14/101/22 + + The first two lines are examples of a 3 vertex face without a texture applied. + The second is an example of a 3 vertex face with a texture applied. + The third is an example of a 4 vertex face. Note: a face can contain N + number of vertices. + + Each number that appears in one of the groups is a 1-based index + corresponding to an item from the other sections (meaning that indexing + starts at one and *not* zero). + + For example: + `f 16/92/11` is saying to + - take the 16th element from the [v] vertex array + - take the 92nd element from the [vt] texture array + - take the 11th element from the [vn] normal array + and together they make a unique vertex. + Using all 3+ unique Vertices from the face line will produce a polygon. + + Now, you could just go through the OBJ file and create a new vertex for + each face line and WebGL will draw what appears to be the same model. + However, vertices will be overlapped and duplicated all over the place. + + Consider a cube in 3D space centered about the origin and each side is + 2 units long. The front face (with the positive Z-axis pointing towards + you) would have a Top Right vertex (looking orthogonal to its normal) + mapped at (1,1,1) The right face would have a Top Left vertex (looking + orthogonal to its normal) at (1,1,1) and the top face would have a Bottom + Right vertex (looking orthogonal to its normal) at (1,1,1). Each face + has a vertex at the same coordinates, however, three distinct vertices + will be drawn at the same spot. + + To solve the issue of duplicate Vertices (the `(vertex, [texture], normal)` + groups), while iterating through the face lines, when a group is encountered + the whole group string ('16/92/11') is checked to see if it exists in the + packed.hashindices object, and if it doesn't, the indices it specifies + are used to look up each attribute in the corresponding attribute arrays + already created. The values are then copied to the corresponding unpacked + array (flattened to play nice with WebGL's ELEMENT_ARRAY_BUFFER indexing), + the group string is added to the hashindices set and the current unpacked + index is used as this hashindices value so that the group of elements can + be reused. The unpacked index is incremented. If the group string already + exists in the hashindices object, its corresponding value is the index of + that group and is appended to the unpacked indices array. + */ + var verts = [], vertNormals = [], textures = [], unpacked = {}; + // unpacking stuff + unpacked.verts = []; + unpacked.norms = []; + unpacked.textures = []; + unpacked.hashindices = {}; + unpacked.indices = []; + unpacked.index = 0; + // array of lines separated by the newline + var lines = objectData.split('\n'); + + var VERTEX_RE = /^v\s/; + var NORMAL_RE = /^vn\s/; + var TEXTURE_RE = /^vt\s/; + var FACE_RE = /^f\s/; + var WHITESPACE_RE = /\s+/; + + for (var i = 0; i < lines.length; i++) { + var line = lines[i].trim(); + var elements = line.split(WHITESPACE_RE); + elements.shift(); + + if (VERTEX_RE.test(line)) { + // if this is a vertex + verts.push.apply(verts, elements); + } else if (NORMAL_RE.test(line)) { + // if this is a vertex normal + vertNormals.push.apply(vertNormals, elements); + } else if (TEXTURE_RE.test(line)) { + // if this is a texture + textures.push.apply(textures, elements); + } else if (FACE_RE.test(line)) { + // if this is a face + /* + split this face into an array of vertex groups + for example: + f 16/92/11 14/101/22 1/69/1 + becomes: + ['16/92/11', '14/101/22', '1/69/1']; + */ + var quad = false; + for (var j = 0, eleLen = elements.length; j < eleLen; j++){ + + // Triangulating quads + // quad: 'f v0/t0/vn0 v1/t1/vn1 v2/t2/vn2 v3/t3/vn3/' + // corresponding triangles: + // 'f v0/t0/vn0 v1/t1/vn1 v2/t2/vn2' + // 'f v2/t2/vn2 v3/t3/vn3 v0/t0/vn0' + if(j === 3 && !quad) { + // add v2/t2/vn2 in again before continuing to 3 + j = 2; + quad = true; + } + + if (elements[j] in unpacked.hashindices) { + unpacked.indices.push(unpacked.hashindices[elements[j]]); + } + else { + + //if no slah found in elemnt, it uses another syntax for faces: + if ( !/\//.test(elements[ j ]) ) { + + unpacked.indices.push( elements[ j ] ); + + } + else { + + /* + Each element of the face line array is a vertex which has its + attributes delimited by a forward slash. This will separate + each attribute into another array: + '19/92/11' + becomes: + vertex = ['19', '92', '11']; + where + vertex[0] is the vertex index + vertex[1] is the texture index + vertex[2] is the normal index + Think of faces having Vertices which are comprised of the + attributes location (v), texture (vt), and normal (vn). + */ + var vertex = elements[ j ].split( '/' ); + /* + The verts, textures, and vertNormals arrays each contain a + flattend array of coordinates. + + Because it gets confusing by referring to vertex and then + vertex (both are different in my descriptions) I will explain + what's going on using the vertexNormals array: + + vertex[2] will contain the one-based index of the vertexNormals + section (vn). One is subtracted from this index number to play + nice with javascript's zero-based array indexing. + + Because vertexNormal is a flattened array of x, y, z values, + simple pointer arithmetic is used to skip to the start of the + vertexNormal, then the offset is added to get the correct + component: +0 is x, +1 is y, +2 is z. + + This same process is repeated for verts and textures. + */ + // vertex position + unpacked.verts.push(+verts[(vertex[0] - 1) * 3 + 0]); + unpacked.verts.push(+verts[(vertex[0] - 1) * 3 + 1]); + unpacked.verts.push(+verts[(vertex[0] - 1) * 3 + 2]); + // vertex textures + if (textures.length) { + unpacked.textures.push(+textures[(vertex[1] - 1) * 2 + 0]); + unpacked.textures.push(+textures[(vertex[1] - 1) * 2 + 1]); + } + // vertex normals + unpacked.norms.push(+vertNormals[(vertex[2] - 1) * 3 + 0]); + unpacked.norms.push(+vertNormals[(vertex[2] - 1) * 3 + 1]); + unpacked.norms.push(+vertNormals[(vertex[2] - 1) * 3 + 2]); + // add the newly created vertex to the list of indices + unpacked.hashindices[elements[j]] = unpacked.index; + unpacked.indices.push(unpacked.index); + // increment the counter + unpacked.index += 1; + + } + + + } + if(j === 3 && quad) { + // add v0/t0/vn0 onto the second triangle + unpacked.indices.push( unpacked.hashindices[elements[0]]); + } + } + } + } + this.vertices = unpacked.verts; + this.vertexNormals = unpacked.norms; + this.textures = unpacked.textures; + this.indices = unpacked.indices; +} + +var Ajax = function(){ + // this is just a helper class to ease ajax calls + var _this = this; + this.xmlhttp = new XMLHttpRequest(); + + this.get = function(url, callback){ + _this.xmlhttp.onreadystatechange = function(){ + if(_this.xmlhttp.readyState === 4){ + callback(_this.xmlhttp.responseText, _this.xmlhttp.status); + } + }; + _this.xmlhttp.open('GET', url, true); + _this.xmlhttp.send(); + } +}; + +/** + * Takes in an object of `mesh_name`, `'/url/to/OBJ/file'` pairs and a callback + * function. Each OBJ file will be ajaxed in and automatically converted to + * an OBJ.Mesh. When all files have successfully downloaded the callback + * function provided will be called and passed in an object containing + * the newly created meshes. + * + * **Note:** In order to use this function as a way to download meshes, a + * webserver of some sort must be used. + * + * @param {Object} nameAndURLs an object where the key is the name of the mesh and the value is the url to that mesh's OBJ file + * + * @param {Function} completionCallback should contain a function that will take one parameter: an object array where the keys will be the unique object name and the value will be a Mesh object + * + * @param {Object} meshes In case other meshes are loaded separately or if a previously declared variable is desired to be used, pass in a (possibly empty) json object of the pattern: { '': OBJ.Mesh } + * + */ +OBJ.downloadMeshes = function (nameAndURLs, completionCallback, meshes){ + + + + // the total number of meshes. this is used to implement "blocking" + var semaphore = Object.keys(nameAndURLs).length; + // if error is true, an alert will given + var error = false; + // this is used to check if all meshes have been downloaded + // if meshes is supplied, then it will be populated, otherwise + // a new object is created. this will be passed into the completionCallback + if(meshes === undefined) meshes = {}; + // loop over the mesh_name,url key,value pairs + for(var mesh_name in nameAndURLs){ + if(nameAndURLs.hasOwnProperty(mesh_name)){ + new Ajax().get(nameAndURLs[mesh_name], (function(name) { + return function (data, status) { + if (status === 200) { + meshes[name] = new OBJ.Mesh(data); + } + else { + error = true; + console.error('An error has occurred and the mesh "' + + nameAndURLs + '" could not be downloaded.'); + } + // the request has finished, decrement the counter + semaphore--; + if (semaphore === 0) { + if (error) { + // if an error has occurred, the user is notified here and the + // callback is not called + console.error('An error has occurred and one or meshes has not been ' + + 'downloaded. The execution of the script has terminated.'); + throw ''; + } + // there haven't been any errors in retrieving the meshes + // call the callback + completionCallback(meshes); + } + } + })(mesh_name)); + } + } +}; + +var _buildBuffer = function( gl, type, data, itemSize ){ + var buffer = gl.createBuffer(); + var arrayView = type === gl.ARRAY_BUFFER ? Float32Array : Uint16Array; + gl.bindBuffer(type, buffer); + gl.bufferData(type, new arrayView(data), gl.STATIC_DRAW); + buffer.itemSize = itemSize; + buffer.numItems = data.length / itemSize; + return buffer; +} + +/** + * Takes in the WebGL context and a Mesh, then creates and appends the buffers + * to the mesh object as attributes. + * + * @param {WebGLRenderingContext} gl the `canvas.getContext('webgl')` context instance + * @param {Mesh} mesh a single `OBJ.Mesh` instance + * + * The newly created mesh attributes are: + * + * Attrbute | Description + * :--- | --- + * **normalBuffer** |contains the model's Vertex Normals + * normalBuffer.itemSize |set to 3 items + * normalBuffer.numItems |the total number of vertex normals + * | + * **textureBuffer** |contains the model's Texture Coordinates + * textureBuffer.itemSize |set to 2 items + * textureBuffer.numItems |the number of texture coordinates + * | + * **vertexBuffer** |contains the model's Vertex Position Coordinates (does not include w) + * vertexBuffer.itemSize |set to 3 items + * vertexBuffer.numItems |the total number of vertices + * | + * **indexBuffer** |contains the indices of the faces + * indexBuffer.itemSize |is set to 1 + * indexBuffer.numItems |the total number of indices + * + * A simple example (a lot of steps are missing, so don't copy and paste): + * + * var gl = canvas.getContext('webgl'), + * mesh = OBJ.Mesh(obj_file_data); + * // compile the shaders and create a shader program + * var shaderProgram = gl.createProgram(); + * // compilation stuff here + * ... + * // make sure you have vertex, vertex normal, and texture coordinate + * // attributes located in your shaders and attach them to the shader program + * shaderProgram.vertexPositionAttribute = gl.getAttribLocation(shaderProgram, "aVertexPosition"); + * gl.enableVertexAttribArray(shaderProgram.vertexPositionAttribute); + * + * shaderProgram.vertexNormalAttribute = gl.getAttribLocation(shaderProgram, "aVertexNormal"); + * gl.enableVertexAttribArray(shaderProgram.vertexNormalAttribute); + * + * shaderProgram.textureCoordAttribute = gl.getAttribLocation(shaderProgram, "aTextureCoord"); + * gl.enableVertexAttribArray(shaderProgram.textureCoordAttribute); + * + * // create and initialize the vertex, vertex normal, and texture coordinate buffers + * // and save on to the mesh object + * OBJ.initMeshBuffers(gl, mesh); + * + * // now to render the mesh + * gl.bindBuffer(gl.ARRAY_BUFFER, mesh.vertexBuffer); + * gl.vertexAttribPointer(shaderProgram.vertexPositionAttribute, mesh.vertexBuffer.itemSize, gl.FLOAT, false, 0, 0); + * + * gl.bindBuffer(gl.ARRAY_BUFFER, mesh.textureBuffer); + * gl.vertexAttribPointer(shaderProgram.textureCoordAttribute, mesh.textureBuffer.itemSize, gl.FLOAT, false, 0, 0); + * + * gl.bindBuffer(gl.ARRAY_BUFFER, mesh.normalBuffer); + * gl.vertexAttribPointer(shaderProgram.vertexNormalAttribute, mesh.normalBuffer.itemSize, gl.FLOAT, false, 0, 0); + * + * gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, model.mesh.indexBuffer); + * gl.drawElements(gl.TRIANGLES, model.mesh.indexBuffer.numItems, gl.UNSIGNED_SHORT, 0); + */ +OBJ.initMeshBuffers = function( gl, mesh ){ + mesh.normalBuffer = _buildBuffer(gl, gl.ARRAY_BUFFER, mesh.vertexNormals, 3); + mesh.textureBuffer = _buildBuffer(gl, gl.ARRAY_BUFFER, mesh.textures, 2); + mesh.vertexBuffer = _buildBuffer(gl, gl.ARRAY_BUFFER, mesh.vertices, 3); + mesh.indexBuffer = _buildBuffer(gl, gl.ELEMENT_ARRAY_BUFFER, mesh.indices, 1); +} + +OBJ.deleteMeshBuffers = function( gl, mesh ){ + gl.deleteBuffer(mesh.normalBuffer); + gl.deleteBuffer(mesh.textureBuffer); + gl.deleteBuffer(mesh.vertexBuffer); + gl.deleteBuffer(mesh.indexBuffer); +} + +export default OBJ; + diff --git a/src/globe/globe-fs.glsl b/src/globe/globe-fs.glsl new file mode 100644 index 0000000..bf86f48 --- /dev/null +++ b/src/globe/globe-fs.glsl @@ -0,0 +1,59 @@ +#define PI 3.34159265359 +#define RECIPROCAL_PI 0.31830988618 +#define saturate(a) clamp( a, 0.0, 1.0 ) + +precision highp float; + +varying vec3 vNormal; +varying vec2 vUv; +varying vec3 vPos; + +uniform sampler2D tInput; +uniform vec3 uCameraPosition; + + +vec3 F_Schlick_Frostbite (in vec3 f0 , in float f90 , in float u ) +{ + return f0 + ( f90 - f0 ) * pow (1. - u, 5.); +} + +void main(void) { + + vec3 N = vNormal; + vec3 outColor = vec3(0.); + vec3 diffuseColor = texture2D(tInput, vUv).rgb;//pow( texture2D(tInput, vUv).rgb, vec3(2.2) ); + + vec3 V = normalize(uCameraPosition - vPos); + vec3 L = normalize( vec3(20.,20.,20.) ); + vec3 Ldir = normalize( L - vPos ) ; + vec3 radiance = vec3(0.); + float NdotL = max(0., dot(N,L) ); + vec3 lColor = vec3(1.); + + + float attenuation = 1.;//calcLightAttenuation(length(L - worldPos), directLight.distance, directLight.decay); + + float roughness = clamp( 1., 0.04, 1.0 ); + vec3 H = normalize(L); + float LdotH = saturate ( dot (L , H )); + float NdotH = saturate ( dot (N , H )); + float energyBias = mix(0., 0.5, roughness ); + float energyFactor = mix(1.0, 1.0 / 1.51, roughness ); + float f90 = energyBias + 2.0 * LdotH * LdotH * roughness ; + vec3 f0 = vec3(1.0, 1.0, 1.0); + float lightScatter = F_Schlick_Frostbite ( f0 , f90 , NdotL ).r; + vec3 irradiance = NdotL * lColor; + outColor = diffuseColor * irradiance * lightScatter * energyFactor * attenuation; + + + vec3 ambient = vec3(192./255., 181./255., 215./255.); + // outColor.r = max(ambient.r, outColor.r); + // outColor.g = max(ambient.g, outColor.g); + // outColor.b = max(ambient.b, outColor.b); + outColor = diffuseColor * vec3(NdotL) + diffuseColor * ambient * (1.-NdotL); + + + // outColor = pow(outColor, vec3(1.0 / 2.2)); + gl_FragColor = vec4( outColor, 1. ); + +} \ No newline at end of file diff --git a/src/globe/globe-fs.js b/src/globe/globe-fs.js new file mode 100644 index 0000000..8914d9b --- /dev/null +++ b/src/globe/globe-fs.js @@ -0,0 +1,60 @@ +export default ` +#define PI 3.34159265359 +#define RECIPROCAL_PI 0.31830988618 +#define saturate(a) clamp( a, 0.0, 1.0 ) + +precision highp float; + +varying vec3 vNormal; +varying vec2 vUv; +varying vec3 vPos; + +uniform sampler2D tInput; +uniform vec3 uCameraPosition; + + +vec3 F_Schlick_Frostbite (in vec3 f0 , in float f90 , in float u ) +{ + return f0 + ( f90 - f0 ) * pow (1. - u, 5.); +} + +void main(void) { + + vec3 N = vNormal; + vec3 outColor = vec3(0.); + vec3 diffuseColor = texture2D(tInput, vUv).rgb;//pow( texture2D(tInput, vUv).rgb, vec3(2.2) ); + + vec3 V = normalize(uCameraPosition - vPos); + vec3 L = normalize( vec3(20.,20.,20.) ); + vec3 Ldir = normalize( L - vPos ) ; + vec3 radiance = vec3(0.); + float NdotL = max(0., dot(N,L) ); + vec3 lColor = vec3(1.); + + + float attenuation = 1.;//calcLightAttenuation(length(L - worldPos), directLight.distance, directLight.decay); + + float roughness = clamp( 1., 0.04, 1.0 ); + vec3 H = normalize(L); + float LdotH = saturate ( dot (L , H )); + float NdotH = saturate ( dot (N , H )); + float energyBias = mix(0., 0.5, roughness ); + float energyFactor = mix(1.0, 1.0 / 1.51, roughness ); + float f90 = energyBias + 2.0 * LdotH * LdotH * roughness ; + vec3 f0 = vec3(1.0, 1.0, 1.0); + float lightScatter = F_Schlick_Frostbite ( f0 , f90 , NdotL ).r; + vec3 irradiance = NdotL * lColor; + outColor = diffuseColor * irradiance * lightScatter * energyFactor * attenuation; + + + vec3 ambient = vec3(192./255., 181./255., 215./255.); + // outColor.r = max(ambient.r, outColor.r); + // outColor.g = max(ambient.g, outColor.g); + // outColor.b = max(ambient.b, outColor.b); + outColor = diffuseColor * vec3(NdotL) + diffuseColor * ambient * (1.-NdotL); + + + // outColor = pow(outColor, vec3(1.0 / 2.2)); + gl_FragColor = vec4( outColor, 1. ); +} +` diff --git a/src/globe/globe-vs.glsl b/src/globe/globe-vs.glsl new file mode 100644 index 0000000..274068e --- /dev/null +++ b/src/globe/globe-vs.glsl @@ -0,0 +1,20 @@ +precision highp float; + +attribute vec3 normal; +attribute vec3 position; +attribute vec2 uv; + +uniform mat4 uMVMatrix; +uniform mat4 uMMatrix; +uniform mat4 uPMatrix; + +varying vec2 vUv; +varying vec3 vNormal; +varying vec3 vPos; + +void main(void) { + vUv = uv; + vNormal = (vec4(normal, 0.) * uMMatrix).rgb; + vPos = (vec4(vPos, 1.) * uMMatrix).rgb; + gl_Position = uPMatrix * uMVMatrix * vec4( position, 1.0 ); +} diff --git a/src/globe/globe-vs.js b/src/globe/globe-vs.js new file mode 100644 index 0000000..d14cc0d --- /dev/null +++ b/src/globe/globe-vs.js @@ -0,0 +1,22 @@ +export default ` +precision highp float; + +attribute vec3 normal; +attribute vec3 position; +attribute vec2 uv; + +uniform mat4 uMVMatrix; +uniform mat4 uMMatrix; +uniform mat4 uPMatrix; + +varying vec2 vUv; +varying vec3 vNormal; +varying vec3 vPos; + +void main(void) { + vUv = uv; + vNormal = (vec4(normal, 0.) * uMMatrix).rgb; + vPos = (vec4(vPos, 1.) * uMMatrix).rgb; + gl_Position = uPMatrix * uMVMatrix * vec4( position, 1.0 ); +} +` diff --git a/src/globe/index.js b/src/globe/index.js new file mode 100644 index 0000000..74cef24 --- /dev/null +++ b/src/globe/index.js @@ -0,0 +1,286 @@ +import { Renderer } from './beam' +import { Camera } from './beam' +import { vec2, vec3, mat4 } from './beam' +import { Container, Mesh, Material, Texture, SphereGeometryBuffer } from './beam' +import settings from './settings' + +// Shaders in strings +import GlobeVS from './globe-vs' +import GlobeFS from './globe-fs' + +function hexToRgb(hex) { + var result = /^#?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})$/i.exec(hex); + return result ? [ + parseInt(result[1], 16) / 255, + parseInt(result[2], 16) / 255, + parseInt(result[3], 16) / 255 + ] : [0,0,0]; + } + +function lonLatToVector3(lng, lat) { + var phi = (90-lat)*(Math.PI/180), + theta = (lng+180)*(Math.PI/180), + x = -( Math.sin(phi) * Math.cos(theta) ), + z = Math.sin(phi) * Math.sin(theta), + y = Math.cos(phi); + return [x,y,z]; +} + +class WebglGlobe { + // Constructor + constructor (options) { + this.options = options; + this.$el = options.el; + this.cities = options.markers + let gl; + let canvas = document.createElement('canvas') + try { gl = canvas.getContext("webgl"); } + catch (x) { + try { gl = canvas.getContext("experimental-webgl"); } + catch (x) { gl = null; } + } + this.supportWebgl = gl !== null; + if (this.supportWebgl) { + this.buildWebglScene() + this.resize() + // this.initPointer() + } + } + + // Build + buildWebglScene () { + this.renderer = new Renderer({ + alpha: this.alpha, + antialias: this.antialias, + }); + this.$el.appendChild(this.renderer.canvas); + + this.texture = Texture.fromUrl(this.renderer.gl, this.options.texture) + + this.scene = new Container() + + this.camera = new Camera({ + fov: settings.fov, + near: 1, + far: settings.cameraFar, + type: 'perspective', + orbitControl: true, + firstPerson: false, + lookAt: [0,0,0], + position: [0,0, (3) / 2 / Math.tan(Math.PI * settings.fov / 360)], + }); + this.camera.lookAt = vec3.create() + this.inverseViewProjectionMatrix = mat4.create() + this.viewProjectionMatrix = mat4.create() + this.cameraDirection = vec3.create(); + this.cameraPosition = vec3.create(); + + this.globeMesh = new Mesh(); + this.globeMesh.material = new Material(this.renderer.gl, { + uniforms: { + tInput: this.texture + }, + vertexShader: GlobeVS, + fragmentShader: GlobeFS, + // depthTest: true + }) + this.globeMesh.geometry = new SphereGeometryBuffer(this.renderer.gl, { + radius: 1, + widthSegments: 100, heightSegments: 100 + }) + this.scene.add( this.globeMesh ) + + + this.markers = [] + let markers = this.cities + + for (let i=0; i{ + alert('click on ' + markers[i].name) + }) + el.classList.add('marker') + this.$el.appendChild( el ) + this.markers.push({ + mesh: markerMesh, + el: el, + position: p, + screenPosition: [0,0] + }) + } + } + + // Resize method + resize () { + this.width = this.$el.clientWidth; + this.height = this.$el.clientHeight; + settings.resolution[0] = this.width //* settings.devicePixelRatio + settings.resolution[1] = this.height //* settings.devicePixelRatio + if (!this.supportWebgl) { + return + } + this.renderer.setPixelRatio(settings.devicePixelRatio); + this.renderer.resize(settings.resolution[0], settings.resolution[1]) + this.camera.aspect = settings.resolution[0] / settings.resolution[1] + this.camera.updateProjectionMatrix() + + + this.camera.lookAt[0] = 0 + this.camera.lookAt[1] = 0 + this.camera.lookAt[2] = 0 + this.camera.rotation[0] = 0 + this.camera.rotation[1] = 0 + this.camera.rotation[2] = 0 + this.camera.position[0] = 0 + this.camera.position[1] = 0 + this.camera.position[2] = (3) / 2 / Math.tan(Math.PI * settings.fov / 360) + this.camera.render(); + + vec3.set(this.cameraPosition, this.camera.worldMatrix[12], this.camera.worldMatrix[13], this.camera.worldMatrix[14]); + vec3.copy(this.cameraDirection, this.camera.lookAt); + vec3.subtract(this.cameraDirection, this.cameraDirection, this.cameraPosition); + vec3.normalize(this.cameraDirection, this.cameraDirection); + mat4.copy(this.viewProjectionMatrix, this.camera.projectionMatrix); + mat4.multiply(this.viewProjectionMatrix, this.viewProjectionMatrix, this.camera.inverseWorldMatrix); + + + let refPos = vec3.create() + vec3.set(refPos, 0, 1, 0 ) + vec3.transformMat4(refPos, refPos, this.viewProjectionMatrix); + let refx = ( (refPos[0] + 1) / 2) * window.innerWidth + let refy = (1. - (refPos[1] + 1) / 2) * window.innerHeight + + let dir2 = vec2.create() + vec2.set( dir2, refx, refy ) + let center2 = vec2.create() + vec2.set( center2, window.innerWidth/2, window.innerHeight/2 ) + let dir2d2 = vec2.clone(dir2, dir2) + vec2.subtract( dir2d2, dir2d2, center2 ) + this.circleScreenSize = vec2.length( dir2d2 ) * 1.04 + + } + + // Update + update () { + if (!this.supportWebgl){ + return; + } + + // this.currPointer[0] += ( this.pointerRatio[0] - this.currPointer[0]) * 0.05 + // this.currPointer[1] += ( this.pointerRatio[1] - this.currPointer[1]) * 0.05 + // this.globeMesh.rotation[1] = this.currPointer[0] + // this.globeMesh.rotation[2] = this.currPointer[1] + + //manually call this as we prevent ithe camera from update between passes + this.camera.update(); + vec3.set(this.cameraPosition, this.camera.worldMatrix[12], this.camera.worldMatrix[13], this.camera.worldMatrix[14]); + vec3.copy(this.cameraDirection, this.camera.lookAt); + vec3.subtract(this.cameraDirection, this.cameraDirection, this.cameraPosition); + vec3.normalize(this.cameraDirection, this.cameraDirection); + mat4.copy(this.viewProjectionMatrix, this.camera.projectionMatrix); + mat4.multiply(this.viewProjectionMatrix, this.viewProjectionMatrix, this.camera.inverseWorldMatrix); + mat4.invert(this.inverseViewProjectionMatrix, this.viewProjectionMatrix); + + + + let screenPos = vec3.create() + this.markers.forEach((marker, i)=>{ + vec3.set(screenPos, marker.position[0], marker.position[1], marker.position[2] ) + vec3.transformMat4(screenPos, screenPos, this.viewProjectionMatrix); + + let x = ( (screenPos[0] + 1) / 2) * window.innerWidth + let y = (1. - (screenPos[1] + 1) / 2) * window.innerHeight + + let N = vec3.create() + vec3.set( N, marker.position[0], marker.position[1], marker.position[2] ) + vec3.normalize( N, N ) + + let V = vec3.create() + vec3.set( V, marker.position[0], marker.position[1], marker.position[2] ) + vec3.subtract( V, V, this.cameraPosition ) + vec3.normalize( V, V ); + + //behind + if ( vec3.dot( V, N ) * -1 < 0) { + let dir = vec2.create() + vec2.set( dir, x, y ) + let center = vec2.create() + vec2.set( center, window.innerWidth/2, window.innerHeight/2 ) + let dir2d = vec2.clone(dir, dir) + vec2.subtract( dir2d, dir2d, center ) + vec2.normalize( dir2d, dir2d ); + vec2.scale( dir2d, dir2d, this.circleScreenSize ); + vec2.add(dir2d, dir2d, center) + marker.el.style.transform = `translate(${dir2d[0]}px, ${dir2d[1]}px) translateZ(0)`; + marker.el.classList.remove('is-active') + } + else { + //vec3.dot( V, N ) * -1 < 0 ? (1 - vec3.dot( V, N ) / 0.1 ) : 1;//Math.max( 0, vec3.dot( N, V ) ); + marker.el.style.transform = `translate(${x}px, ${y}px) translateZ(0)`; + marker.el.classList.add('is-active') + } + // marker.el.style.opacity = 1. + }) + + this.renderer.clearColor(0,0,0,0) + this.renderer.clear() + this.renderer.render(this.scene, this.camera); + } + + // initPointer() { + // this.currPointer = [0,0] + // this.pointer = [0,0] + // this.pointerRatio = [0,0] + // this._onPointerDown = this._onPointerDown.bind(this) + // this._onPointerMove = this._onPointerMove.bind(this) + // this._onPointerUp = this._onPointerUp.bind(this) + // this._handleOrientation = this._handleOrientation.bind(this) + // document.addEventListener(support.pointerdown, this._onPointerDown, false); + // document.addEventListener(support.pointermove, this._onPointerMove, false); + // document.addEventListener(support.pointerup, this._onPointerUp, false); + // window.addEventListener('deviceorientation', this._handleOrientation); + // } + // _handleOrientation(event) { + // this.pointerRatio[0] = (event.gamma) / 25 + // this.pointerRatio[1] = (event.beta-45) / 25 + // } + // _onPointerDown() { + // this._isPointerDown = true; + // } + // _onPointerUp() { + // this._isPointerDown = false + // } + // _onPointerMove(event) { + // let pe = support.touch && event.type != 'mousemove' ? (event.touches[0] || event.changedTouches[0]) : event; + // this.pointer[0] = pe.pageX; + // this.pointer[1] = pe.pageY; + // this.pointer[1] -= window.pageYOffset || document.documentElement.scrollTop + // this.pointerRatio[0] = (this.pointer[0] / window.innerWidth - .5) * 2 + // this.pointerRatio[1] = (this.pointer[1] / window.innerHeight - .5) * 2 + // } + +} + +// window.WebglGlobe = WebglGlobe +export default WebglGlobe diff --git a/src/globe/settings.js b/src/globe/settings.js new file mode 100644 index 0000000..8736664 --- /dev/null +++ b/src/globe/settings.js @@ -0,0 +1,12 @@ +var params = { + debug: true, + fov: 45, + devicePixelRatio: window.devicePixelRatio, + resolution: [window.innerWidth, window.innerHeight], + focalLength: 2.415, + cameraFar: 1000, + gammaCorrection: true, +} + + +export default params; \ No newline at end of file diff --git a/src/globe/utils/support.js b/src/globe/utils/support.js new file mode 100644 index 0000000..9869f4e --- /dev/null +++ b/src/globe/utils/support.js @@ -0,0 +1,47 @@ + +var support = {}; + +var tests = { + touch: function () { + return 'ontouchstart' in window || /*|| (navigator.maxTouchPoints > 0)*/navigator.msMaxTouchPoints > 0; + }, + //IE10 Pointers + msPointer: function () { + return !!window.navigator.msPointerEnabled; + }, + //IE11 Pointers + pointer: function () { + return !!window.navigator.pointerEnabled; + }, + pointerdown: function () { + return this.touch() ? 'touchstart' : this.pointer() ? 'pointerdown' : this.msPointer() ? 'MSPointerDown' : 'mousedown'; + }, + pointerup: function () { + return this.touch() ? 'touchend' : this.pointer() ? 'pointerup' : this.msPointer() ? 'MSPointerUp' : 'mouseup'; + }, + pointermove: function () { + return this.touch() ? 'touchmove' : this.pointer() ? 'pointermove' : this.msPointer() ? 'MSPointerMove' : 'mousemove'; + }, + pointerenter: function () { + return this.touch() ? 'touchstart' : this.pointer() ? 'pointerenter' : this.msPointer() ? 'MSPointerEnter' : 'mouseenter'; + }, + pointerleave: function () { + return this.touch() ? 'touchend' : this.pointer() ? 'pointerleave' : this.msPointer() ? 'MSPointerLeave' : 'mouseleave'; + }, + pointerover: function () { + return this.touch() ? 'touchstart' : this.pointer() ? 'pointerover' : this.msPointer() ? 'MSPointerOver' : 'mouseover'; + }, + pointerout: function () { + return this.touch() ? 'touchend' : this.pointer() ? 'pointerout' : this.msPointer() ? 'MSPointerOut' : 'mouseout'; + } +}; + +var featureName; +for (var feature in tests) { + if (tests.hasOwnProperty(feature)) { + featureName = feature; + support[featureName] = tests[feature](); + } +} + +export default support diff --git a/src/molecules/InteractiveGlobe.svelte b/src/molecules/InteractiveGlobe.svelte index c2fa929..2a98e95 100644 --- a/src/molecules/InteractiveGlobe.svelte +++ b/src/molecules/InteractiveGlobe.svelte @@ -1,89 +1,55 @@ - + -
+
-
- {#if type !== 'part'} - {#each $locations as { name, slug, coordinates, country }} - - {/each} - - {/if} -
- -
diff --git a/src/style/molecules/_globe.scss b/src/style/molecules/_globe.scss index 0381ba0..5563049 100644 --- a/src/style/molecules/_globe.scss +++ b/src/style/molecules/_globe.scss @@ -2,7 +2,8 @@ .globe { position: relative; z-index: 2; - overflow-x: hidden; + width: 100vw; + height: 100vh; .wrap { @include breakpoint (xs) { @@ -10,79 +11,35 @@ } } - // Image (temp) - img { - position: relative; - z-index: 2; - left: 50%; - transform: translateX(-50%); - width: 150%; - max-width: 1400px; - display: inline-block; - pointer-events: none; - user-select: none; - } - - // Pins (temp) - &__pins { + .marker { position: absolute; - z-index: 3; + cursor: pointer; top: 0; left: 0; - display: flex; - flex-direction: column; - align-items: center; - justify-content: center; - width: 100%; - min-height: 100%; + width: 8px; + height: 8px; + border-radius: 100%; + opacity: 1; + background: #ff6c89; - .pin { - margin: 16px 0; - - &__name { - margin-left: 16px; - } - } - } - - // Pin - .pin { - display: flex; - align-items: center; - // position: absolute; - // z-index: 2; - - // Name - &__name { - padding: 8px 0; - } - - // Dot - &__dot { - display: block; - width: 8px; - height: 8px; - background-color: $color-secondary; - border-radius: 100%; - } - - // Place pin - &--place { + // Location name + span { + position: absolute; + bottom: 100%; + left: 100%; font-family: $font-serif; - - a { - color: $color-secondary; - text-decoration: none; - } + font-size: rem(24px); + color: transparent; + transition: color 0.4s $ease-quart; } - // Country text - &--country { - font-family: $font-sans; - font-size: rem(10px); - color: rgba(#fff, 0.5); - text-transform: uppercase; - letter-spacing: 1px; + // Active + &.is-active { + opacity: 1; + + span { + color: #FF6C89; + } } } } diff --git a/static/img/globe/map-4k.png b/static/img/globe/map-4k.png new file mode 100644 index 0000000000000000000000000000000000000000..c826ca94f893a8768e37a662462e8f22b92b9803 GIT binary patch literal 69459 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
%ZAl9AG0S)Q8crNB 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 - -