fix merge

This commit is contained in:
2020-04-18 23:24:43 +02:00
67 changed files with 558 additions and 7126 deletions

View File

@@ -58,6 +58,7 @@
"rollup-plugin-terser": "^5.3.0", "rollup-plugin-terser": "^5.3.0",
"sapper": "^0.27.12", "sapper": "^0.27.12",
"svelte": "^3.20.1", "svelte": "^3.20.1",
"svelte-lazy": "^0.1.10",
"svelte-preprocess": "^3.7.1" "svelte-preprocess": "^3.7.1"
}, },
"browserslist": [ "browserslist": [

75
pnpm-lock.yaml generated
View File

@@ -7,6 +7,7 @@ dependencies:
polka: 1.0.0-next.11 polka: 1.0.0-next.11
scroll-out: 2.2.8 scroll-out: 2.2.8
sirv: 0.4.2 sirv: 0.4.2
svelte-lazy: 0.1.10
swipe-listener: 1.1.0 swipe-listener: 1.1.0
devDependencies: devDependencies:
'@babel/core': 7.9.0 '@babel/core': 7.9.0
@@ -72,7 +73,7 @@ packages:
gensync: 1.0.0-beta.1 gensync: 1.0.0-beta.1
json5: 2.1.3 json5: 2.1.3
lodash: 4.17.15 lodash: 4.17.15
resolve: 1.15.1 resolve: 1.16.0
semver: 5.7.1 semver: 5.7.1
source-map: 0.5.7 source-map: 0.5.7
dev: true dev: true
@@ -698,7 +699,7 @@ packages:
'@babel/core': 7.9.0 '@babel/core': 7.9.0
'@babel/helper-module-imports': 7.8.3 '@babel/helper-module-imports': 7.8.3
'@babel/helper-plugin-utils': 7.8.3 '@babel/helper-plugin-utils': 7.8.3
resolve: 1.15.1 resolve: 1.16.0
semver: 5.7.1 semver: 5.7.1
dev: true dev: true
peerDependencies: peerDependencies:
@@ -917,7 +918,7 @@ packages:
estree-walker: 1.0.1 estree-walker: 1.0.1
is-reference: 1.1.4 is-reference: 1.1.4
magic-string: 0.25.7 magic-string: 0.25.7
resolve: 1.15.1 resolve: 1.16.0
rollup: 2.6.1 rollup: 2.6.1
dev: true dev: true
engines: engines:
@@ -932,7 +933,7 @@ packages:
'@types/resolve': 0.0.8 '@types/resolve': 0.0.8
builtin-modules: 3.1.0 builtin-modules: 3.1.0
is-module: 1.0.0 is-module: 1.0.0
resolve: 1.15.1 resolve: 1.16.0
rollup: 2.6.1 rollup: 2.6.1
dev: true dev: true
engines: engines:
@@ -1159,7 +1160,7 @@ packages:
/autoprefixer/9.7.6: /autoprefixer/9.7.6:
dependencies: dependencies:
browserslist: 4.11.1 browserslist: 4.11.1
caniuse-lite: 1.0.30001040 caniuse-lite: 1.0.30001042
chalk: 2.4.2 chalk: 2.4.2
normalize-range: 0.1.2 normalize-range: 0.1.2
num2fraction: 1.2.2 num2fraction: 1.2.2
@@ -1191,7 +1192,7 @@ packages:
glob: 7.1.6 glob: 7.1.6
pkg-up: 3.1.0 pkg-up: 3.1.0
reselect: 4.0.0 reselect: 4.0.0
resolve: 1.15.1 resolve: 1.16.0
dev: true dev: true
engines: engines:
node: '>= 8.0.0' node: '>= 8.0.0'
@@ -1239,8 +1240,8 @@ packages:
integrity: sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A== integrity: sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==
/browserslist/4.11.1: /browserslist/4.11.1:
dependencies: dependencies:
caniuse-lite: 1.0.30001040 caniuse-lite: 1.0.30001042
electron-to-chromium: 1.3.403 electron-to-chromium: 1.3.412
node-releases: 1.1.53 node-releases: 1.1.53
pkg-up: 2.0.0 pkg-up: 2.0.0
dev: true dev: true
@@ -1319,10 +1320,10 @@ packages:
node: '>=0.10.0' node: '>=0.10.0'
resolution: resolution:
integrity: sha1-MvxLn82vhF/N9+c7uXysImHwqwo= integrity: sha1-MvxLn82vhF/N9+c7uXysImHwqwo=
/caniuse-lite/1.0.30001040: /caniuse-lite/1.0.30001042:
dev: true dev: true
resolution: resolution:
integrity: sha512-Ep0tEPeI5wCvmJNrXjE3etgfI+lkl1fTDU6Y3ZH1mhrjkPlVI9W4pcKbMo+BQLpEWKVYYp2EmYaRsqpPC3k7lQ== integrity: sha512-igMQ4dlqnf4tWv0xjaaE02op9AJ2oQzXKjWf4EuAHFN694Uo9/EfPVIPJcmn2WkU9RqozCxx5e2KPcVClHDbDw==
/caseless/0.12.0: /caseless/0.12.0:
dev: true dev: true
resolution: resolution:
@@ -1378,10 +1379,10 @@ packages:
node: '>=8' node: '>=8'
resolution: resolution:
integrity: sha512-I/zHAwsKf9FqGoXM4WWRACob9+SNukZTd94DWF57E4toouRulbCxcUh6RKUEOQlYTHJnzkPMySvPNaaSLNfLZw== integrity: sha512-I/zHAwsKf9FqGoXM4WWRACob9+SNukZTd94DWF57E4toouRulbCxcUh6RKUEOQlYTHJnzkPMySvPNaaSLNfLZw==
/cli-width/2.2.0: /cli-width/2.2.1:
dev: true dev: true
resolution: resolution:
integrity: sha1-/xnt6Kml5XkyQUewwR8PvLq+1jk= integrity: sha512-GRMWDxpOB6Dgk2E5Uo+3eEBvtOOlimMmpbFiKuLFnQzYDavtLFY3K5ona41jgN/WdRZtG7utuVSVTL4HbZHGkw==
/cliui/3.2.0: /cliui/3.2.0:
dependencies: dependencies:
string-width: 1.0.2 string-width: 1.0.2
@@ -1670,10 +1671,10 @@ packages:
dev: true dev: true
resolution: resolution:
integrity: sha1-OoOpBOVDUyh4dMVkt1SThoSamMk= integrity: sha1-OoOpBOVDUyh4dMVkt1SThoSamMk=
/electron-to-chromium/1.3.403: /electron-to-chromium/1.3.412:
dev: true dev: true
resolution: resolution:
integrity: sha512-JaoxV4RzdBAZOnsF4dAlZ2ijJW72MbqO5lNfOBHUWiBQl3Rwe+mk2RCUMrRI3rSClLJ8HSNQNqcry12H+0ZjFw== integrity: sha512-4bVdSeJScR8fT7ERveLWbxemY5uXEHVseqMRyORosiKcTUSGtVwBkV8uLjXCqoFLeImA57Z9hbz3TOid01U4Hw==
/emoji-regex/7.0.3: /emoji-regex/7.0.3:
dev: true dev: true
resolution: resolution:
@@ -1760,7 +1761,7 @@ packages:
/eslint-import-resolver-node/0.3.3: /eslint-import-resolver-node/0.3.3:
dependencies: dependencies:
debug: 2.6.9 debug: 2.6.9
resolve: 1.15.1 resolve: 1.16.0
dev: true dev: true
resolution: resolution:
integrity: sha512-b8crLDo0M5RSe5YG8Pu2DYBj71tSB6OvXkfzwbJU2w7y8P4/yo0MyF8jU26IEuEuHF2K5/gcAJE3LhQGqBBbVg== integrity: sha512-b8crLDo0M5RSe5YG8Pu2DYBj71tSB6OvXkfzwbJU2w7y8P4/yo0MyF8jU26IEuEuHF2K5/gcAJE3LhQGqBBbVg==
@@ -1797,7 +1798,7 @@ packages:
minimatch: 3.0.4 minimatch: 3.0.4
object.values: 1.1.1 object.values: 1.1.1
read-pkg-up: 2.0.0 read-pkg-up: 2.0.0
resolve: 1.15.1 resolve: 1.16.0
dev: true dev: true
engines: engines:
node: '>=4' node: '>=4'
@@ -1811,7 +1812,7 @@ packages:
eslint-utils: 2.0.0 eslint-utils: 2.0.0
ignore: 5.1.4 ignore: 5.1.4
minimatch: 3.0.4 minimatch: 3.0.4
resolve: 1.15.1 resolve: 1.16.0
semver: 6.3.0 semver: 6.3.0
dev: true dev: true
engines: engines:
@@ -1884,7 +1885,7 @@ packages:
eslint-utils: 1.4.3 eslint-utils: 1.4.3
eslint-visitor-keys: 1.1.0 eslint-visitor-keys: 1.1.0
espree: 6.2.1 espree: 6.2.1
esquery: 1.2.0 esquery: 1.3.1
esutils: 2.0.3 esutils: 2.0.3
file-entry-cache: 5.0.1 file-entry-cache: 5.0.1
functional-red-black-tree: 1.0.1 functional-red-black-tree: 1.0.1
@@ -1934,14 +1935,14 @@ packages:
hasBin: true hasBin: true
resolution: resolution:
integrity: sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A== integrity: sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==
/esquery/1.2.0: /esquery/1.3.1:
dependencies: dependencies:
estraverse: 5.0.0 estraverse: 5.1.0
dev: true dev: true
engines: engines:
node: '>=8.0' node: '>=0.10'
resolution: resolution:
integrity: sha512-weltsSqdeWIX9G2qQZz7KlTRJdkkOCTPgLYJUz1Hacf48R4YOwGPHO3+ORfWedqJKbq5WQmsgK90n+pFLIKt/Q== integrity: sha512-olpvt9QG0vniUBZspVRN6lwB7hOZoTRtT+jzR+tS4ffYx2mzbw+z0XCOk44aaLYKApNX5nMm+E+P6o25ip/DHQ==
/esrecurse/4.2.1: /esrecurse/4.2.1:
dependencies: dependencies:
estraverse: 4.3.0 estraverse: 4.3.0
@@ -1956,12 +1957,12 @@ packages:
node: '>=4.0' node: '>=4.0'
resolution: resolution:
integrity: sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw== integrity: sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==
/estraverse/5.0.0: /estraverse/5.1.0:
dev: true dev: true
engines: engines:
node: '>=4.0' node: '>=4.0'
resolution: resolution:
integrity: sha512-j3acdrMzqrxmJTNj5dbr1YbjacrYgAxVMeF0gK16E3j494mOe7xygM/ZLIguEQ0ETwAg2hlJCtHRGav+y0Ny5A== integrity: sha512-FyohXK+R0vE+y1nHLoBM7ZTyqRpqAlhdZHCWIWEviFLiGB8b04H6bQs8G+XTthacvT8VuwvteiP7RJSxMs8UEw==
/estree-walker/0.6.1: /estree-walker/0.6.1:
dev: true dev: true
resolution: resolution:
@@ -2336,7 +2337,7 @@ packages:
graceful-fs: 4.2.3 graceful-fs: 4.2.3
inherits: 2.0.4 inherits: 2.0.4
map-limit: 0.0.1 map-limit: 0.0.1
resolve: 1.15.1 resolve: 1.16.0
dev: true dev: true
resolution: resolution:
integrity: sha512-Ogm179MCazwIRyEqs3g3EOY4Y3XIAa0yl8J5RE9rJC6QH1w8weVOp2RZu0mvnYy/2xIas1w166YR2eZdDkWQxg== integrity: sha512-Ogm179MCazwIRyEqs3g3EOY4Y3XIAa0yl8J5RE9rJC6QH1w8weVOp2RZu0mvnYy/2xIas1w166YR2eZdDkWQxg==
@@ -2352,7 +2353,7 @@ packages:
glslify-bundle: 5.1.1 glslify-bundle: 5.1.1
glslify-deps: 1.3.1 glslify-deps: 1.3.1
minimist: 1.2.5 minimist: 1.2.5
resolve: 1.15.1 resolve: 1.16.0
stack-trace: 0.0.9 stack-trace: 0.0.9
static-eval: 2.0.5 static-eval: 2.0.5
through2: 2.0.5 through2: 2.0.5
@@ -2435,7 +2436,7 @@ packages:
he: 1.2.0 he: 1.2.0
param-case: 2.1.1 param-case: 2.1.1
relateurl: 0.2.7 relateurl: 0.2.7
uglify-js: 3.8.1 uglify-js: 3.9.1
dev: true dev: true
engines: engines:
node: '>=6' node: '>=6'
@@ -2558,7 +2559,7 @@ packages:
ansi-escapes: 4.3.1 ansi-escapes: 4.3.1
chalk: 3.0.0 chalk: 3.0.0
cli-cursor: 3.1.0 cli-cursor: 3.1.0
cli-width: 2.2.0 cli-width: 2.2.1
external-editor: 3.1.0 external-editor: 3.1.0
figures: 3.2.0 figures: 3.2.0
lodash: 4.17.15 lodash: 4.17.15
@@ -3128,7 +3129,7 @@ packages:
/normalize-package-data/2.5.0: /normalize-package-data/2.5.0:
dependencies: dependencies:
hosted-git-info: 2.8.8 hosted-git-info: 2.8.8
resolve: 1.15.1 resolve: 1.16.0
semver: 5.7.1 semver: 5.7.1
validate-npm-package-license: 3.0.4 validate-npm-package-license: 3.0.4
dev: true dev: true
@@ -3680,7 +3681,7 @@ packages:
dependencies: dependencies:
autoprefixer: 9.7.6 autoprefixer: 9.7.6
browserslist: 4.11.1 browserslist: 4.11.1
caniuse-lite: 1.0.30001040 caniuse-lite: 1.0.30001042
css-blank-pseudo: 0.1.4 css-blank-pseudo: 0.1.4
css-has-pseudo: 0.10.0 css-has-pseudo: 0.10.0
css-prefers-color-scheme: 3.1.1 css-prefers-color-scheme: 3.1.1
@@ -4044,12 +4045,12 @@ packages:
dev: true dev: true
resolution: resolution:
integrity: sha1-3ZV5gufnNt699TtYpN2RdUV13UY= integrity: sha1-3ZV5gufnNt699TtYpN2RdUV13UY=
/resolve/1.15.1: /resolve/1.16.0:
dependencies: dependencies:
path-parse: 1.0.6 path-parse: 1.0.6
dev: true dev: true
resolution: resolution:
integrity: sha512-84oo6ZTtoTUpjgNEr5SJyzQhzL72gaRodsSfyxC/AXRvwu0Yse9H8eF9IpGo7b8YetZhlI6v7ZQ6bKBFV/6S7w== integrity: sha512-LarL/PIKJvc09k1jaeT4kQb/8/7P+qV4qSnN2K80AES+OHdfZELAKVOBjxsvtToT/uLOfFbvYvKfZmV8cee7nA==
/restore-cursor/3.1.0: /restore-cursor/3.1.0:
dependencies: dependencies:
onetime: 5.1.0 onetime: 5.1.0
@@ -4544,6 +4545,10 @@ packages:
node: '>=8' node: '>=8'
resolution: resolution:
integrity: sha512-oRSIpR8pxT1Wr2FquTNnGet79b3BWljqOuoW/h4oBhxJ/HUbX5nX6JSruTkvXDCFMwDPvsaTTbvMLKZWSy0R5g== integrity: sha512-oRSIpR8pxT1Wr2FquTNnGet79b3BWljqOuoW/h4oBhxJ/HUbX5nX6JSruTkvXDCFMwDPvsaTTbvMLKZWSy0R5g==
/svelte-lazy/0.1.10:
dev: false
resolution:
integrity: sha512-3MobAvIUe345ZNREDvy/3tsfZMzPcSW+fE7osCVtGOAFeQ25haqQoZhT2c6qxxnWB7oVlTXTHCfEatzAGJi0fQ==
/svelte-preprocess/3.7.1_svelte@3.20.1: /svelte-preprocess/3.7.1_svelte@3.20.1:
dependencies: dependencies:
'@types/pug': 2.0.4 '@types/pug': 2.0.4
@@ -4710,16 +4715,15 @@ packages:
dev: true dev: true
resolution: resolution:
integrity: sha1-hnrHTjhkGHsdPUfZlqeOxciDB3c= integrity: sha1-hnrHTjhkGHsdPUfZlqeOxciDB3c=
/uglify-js/3.8.1: /uglify-js/3.9.1:
dependencies: dependencies:
commander: 2.20.3 commander: 2.20.3
source-map: 0.6.1
dev: true dev: true
engines: engines:
node: '>=0.8.0' node: '>=0.8.0'
hasBin: true hasBin: true
resolution: resolution:
integrity: sha512-W7KxyzeaQmZvUFbGj4+YFshhVrMBGSg2IbcYAjGWGvx8DHvJMclbTDMpffdxFUGPBHjIytk7KJUR/KUXstUGDw== integrity: sha512-JUPoL1jHsc9fOjVFHdQIhqEEJsQvfKDjlubcCilu8U26uZ73qOg8VsN8O1jbuei44ZPlwL7kmbAdM4tzaUvqnA==
/unicode-canonical-property-names-ecmascript/1.0.4: /unicode-canonical-property-names-ecmascript/1.0.4:
dev: true dev: true
engines: engines:
@@ -4925,5 +4929,6 @@ specifiers:
scroll-out: ^2.2.8 scroll-out: ^2.2.8
sirv: ^0.4.2 sirv: ^0.4.2
svelte: ^3.20.1 svelte: ^3.20.1
svelte-lazy: ^0.1.10
svelte-preprocess: ^3.7.1 svelte-preprocess: ^3.7.1
swipe-listener: ^1.1.0 swipe-listener: ^1.1.0

View File

@@ -130,20 +130,21 @@ export default {
/* /*
** Service worker ** Service worker
*/ */
serviceworker: { // ...(!dev && {
input: sapperConfig.serviceworker.input(), // serviceworker: {
output: sapperConfig.serviceworker.output(), // input: sapperConfig.serviceworker.input(),
plugins: [ // output: sapperConfig.serviceworker.output(),
resolve(), // plugins: [
aliases, // resolve(),
replace({ // aliases,
'process.browser': true, // replace({
...replaceOptions // 'process.browser': true,
}), // ...replaceOptions
commonjs(), // }),
!dev && terser() // commonjs(),
], // !dev && terser()
// ],
onwarn, // onwarn,
} // }
// })
} }

View File

@@ -10,7 +10,7 @@ export const animateIn = scope => {
const tl = anime.timeline({ const tl = anime.timeline({
easing: 'easeOutQuart', easing: 'easeOutQuart',
duration: animDuration, duration: animDuration,
delay: animDelay, // delay: animDelay,
autoplay: false autoplay: false
}) })

View File

@@ -18,7 +18,7 @@ export const animateIn = () => {
duration: animDuration duration: animDuration
}) })
// Parallax on scroll // Title: Parallax on scroll
const translate = anime({ const translate = anime({
targets: '#title-houses', targets: '#title-houses',
translateX: ['7%', '-15%'], translateX: ['7%', '-15%'],

View File

@@ -40,8 +40,7 @@ export const animateIn = () => {
// Illustration // Illustration
tl.add({ tl.add({
targets: '.place__illustration', targets: '.place__illustration',
scale: [1.1, 1], scale: [1.05, 1],
translateX: ['-50%', '-50%'],
translateZ: [0, 0], translateZ: [0, 0],
opacity: [0, 1] opacity: [0, 1]
}, 0) }, 0)

View File

@@ -1,120 +0,0 @@
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;

View File

@@ -319,75 +319,9 @@ class Camera extends Object3d {
this.position[0] = Math.sin(this.currTheta) * Math.cos(this.phi) * this._cameraDistance; this.position[0] = Math.sin(this.currTheta) * Math.cos(this.phi) * this._cameraDistance;
this.position[1] = Math.sin(this.phi) * this._cameraDistance; this.position[1] = Math.sin(this.phi) * this._cameraDistance;
this.position[2] = Math.cos(this.currTheta) * Math.cos(this.phi) * this._cameraDistance; this.position[2] = Math.cos(this.currTheta) * Math.cos(this.phi) * this._cameraDistance;
this.lookAt[0] = 0.000000001//this.pointerXMove / -100;
this.lookAt[1] = 0.000000001//this.pointerYMove / 100;
this.lookAt[2] = 0.000000001
super.render(); super.render();
} }
} }
else if (this.firstPerson)
{
if (this._canUpdate || force) {
var time = Date.now();
var delta = ( time - this.time ) / 1000;
this.prevTime = time;
this._velocity[0] -= this._velocity[0] * 10.0 * delta;
this._velocity[1] -= this._velocity[1] * 10.0 * delta;
this._velocity[2] -= this._velocity[2] * 10.0 * delta;
if (this.position[1] < 0 && this._velocity[1] < 0) {
this._velocity[1] = 0;
this.position[1] = 0
}
if ( this._moveForward ) this._velocity[2] -= (this.moveSpeed) * delta;
if ( this._moveBackward ) this._velocity[2] += (this.moveSpeed) * delta;
if ( this._moveLeft ) this._velocity[0] -= (this.moveSpeed) * delta;
if ( this._moveRight ) this._velocity[0] += (this.moveSpeed) * delta;
this._camera[0] = this._velocity[0];
this._camera[1] = this._velocity[1];
this._camera[2] = this._velocity[2];
this.currTheta += (this.theta - this.currTheta) * 0.2;
this.currPhi += (this.phi - this.currPhi) * 0.2;
//first we reset position to center and rotate the camera
this._oldPosition[0] = this.position[0];
this._oldPosition[1] = this.position[1];
this._oldPosition[2] = this.position[2];
this.position[0] = 0;
this.position[1] = 0;
this.position[2] = 0;
this.lookAt[0] = Math.sin(this.currTheta) * Math.cos(this.currPhi) * this._cameraDistance ;
this.lookAt[1] = Math.sin(this.currPhi) * this._cameraDistance * -1 ;
this.lookAt[2] = Math.cos(this.currTheta) * Math.cos(this.currPhi) * this._cameraDistance ;
this.updateMatrix()
//then we translate the camera based on velocity to folow view direction
var _matrix = mat4.create();
mat4.copy(_matrix, this.matrix);
mat4.translate( _matrix, _matrix, this._camera);
var _pos = vec3.create()
mat4.getTranslation(_pos, _matrix);
this.position[0] = this._oldPosition[0] + _pos[0]
this.position[1] = this._oldPosition[1] + _pos[1]
this.position[2] = this._oldPosition[2] + _pos[2]
this.lookAt[0] = Math.sin(this.currTheta) * Math.cos(this.currPhi) * this._cameraDistance + this.position[0];
this.lookAt[1] = Math.sin(this.currPhi) * this._cameraDistance * -1 + this.position[1];
this.lookAt[2] = Math.cos(this.currTheta) * Math.cos(this.currPhi) * this._cameraDistance + this.position[2];
this.updateMatrix();
this.updateWorldMatrix();
this.time = time;
}
}
else { else {
super.render(); super.render();
} }

View File

@@ -1,155 +0,0 @@
import uuid from './utils/uuid';
import getFilter from './utils/getFilter';
import isPowerOf2 from './utils/isPowerOf2';
class CubeTexture {
constructor(gl, options) {
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,
urls: null
}, 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_CUBE_MAP, this._texture);
gl.texParameteri(gl.TEXTURE_CUBE_MAP, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE);
gl.texParameteri(gl.TEXTURE_CUBE_MAP, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE);
gl.texParameteri(gl.TEXTURE_CUBE_MAP, gl.TEXTURE_MIN_FILTER, gl.LINEAR);
gl.texParameteri(gl.TEXTURE_CUBE_MAP, gl.TEXTURE_MAG_FILTER, gl.LINEAR);
gl.texImage2D(gl.TEXTURE_CUBE_MAP_POSITIVE_X, 0, this.format, this.width, this.height, 0, this.format, this.type, new Uint8Array(new Array(this.width*this.height*4)));
gl.texImage2D(gl.TEXTURE_CUBE_MAP_NEGATIVE_X, 0, this.format, this.width, this.height, 0, this.format, this.type, new Uint8Array(new Array(this.width*this.height*4)));
gl.texImage2D(gl.TEXTURE_CUBE_MAP_POSITIVE_Y, 0, this.format, this.width, this.height, 0, this.format, this.type, new Uint8Array(new Array(this.width*this.height*4)));
gl.texImage2D(gl.TEXTURE_CUBE_MAP_NEGATIVE_Y, 0, this.format, this.width, this.height, 0, this.format, this.type, new Uint8Array(new Array(this.width*this.height*4)));
gl.texImage2D(gl.TEXTURE_CUBE_MAP_POSITIVE_Z, 0, this.format, this.width, this.height, 0, this.format, this.type, new Uint8Array(new Array(this.width*this.height*4)));
gl.texImage2D(gl.TEXTURE_CUBE_MAP_NEGATIVE_Z, 0, this.format, this.width, this.height, 0, this.format, this.type, new Uint8Array(new Array(this.width*this.height*4)));
gl.bindTexture( gl.TEXTURE_CUBE_MAP, null);
// /**
// * add getter and setter to update texture_wrap when this.wrap changes
// */
// Object.defineProperty(this, 'wrapS', {
// set: (value) => {
// 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;

View File

@@ -1,64 +0,0 @@
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;

View File

@@ -1,231 +0,0 @@
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;

View File

@@ -1,74 +0,0 @@
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;

View File

@@ -1,207 +0,0 @@
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;

View File

@@ -1,84 +0,0 @@
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<this.vertices.length/3;i++) {
if (needsUvs) {
this.uvs.push( 0,0 )
}
if (needsNormals) {
this.normals.push( 0,1,0 );
}
}
this.attributes['index'] = new ArrayBuffer(this.gl, new Uint16Array(this.indices), 1, true);
this.attributes['position'] = new ArrayBuffer(this.gl, new Float32Array(this.vertices), 3, false);
this.attributes['normal'] = new ArrayBuffer(this.gl, new Float32Array(this.normals), 3, false);
this.attributes['uv'] = new ArrayBuffer(this.gl, new Float32Array(this.uvs), 2, false);
// this.computeBoundingSphere();
this.options.onLoaded()
}
}
export default JSONGeometryBuffer;

View File

@@ -1,98 +0,0 @@
import {Object3d} from 'beam';
import {vec3, mat4} from 'beam';
import {Camera} from 'beam';
class Light extends Object3d {
constructor(options={}) {
options = Object.assign({},{
color: [1,1,1],
direction: [-1,-1,0],
position: [1,1,1],
intensity: 1,
distance: 1000000,
decay: 1,
angle: Math.PI/4,
exponent: 1,
castShadow: false,
penumbra: 0,
lookAt: vec3.create(),
shadowMap: true,
shadowMapWidth: 256,
shadowMapHeight: 256,
}, options)
super(options)
this.color = options.color;
this.intensity = options.intensity;
this.position = options.position;
this.distance = options.distance;
this.decay = options.decay;
this.angle = options.angle;
this.exponent = options.exponent;
this.penumbra = options.penumbra;
this.castShadow = options.castShadow;
this.lookAt = options.lookAt;
if (options.shadowMap) {
this.shadowMap = true;
this._cacheAngle = this.angle;
this.shadowMapCamera = new Camera({
near: 1,
far: this.distance,
type: 'perspective',
fov: ( 2 * this.angle ) * 180 / Math.PI,
aspect: 1,
});
this.shadowMapCamera.lookAt = vec3.create();
}
}
update() {
this.updateMatrix();
this.updateWorldMatrix();
if (this.shadowMap) {
// if (this._cacheAngle !== this.angle) {
// this._cacheAngle = this.angle;
this.shadowMapCamera.fov = ( 2 * this.angle ) * 180 / Math.PI;
this.shadowMapCamera.updateProjectionMatrix()
// }
//TODO: make the camera a child of the light object
// instead of copy all props
this.shadowMapCamera.position[0] = this.position[0];
this.shadowMapCamera.position[1] = this.position[1];
this.shadowMapCamera.position[2] = this.position[2];
this.shadowMapCamera.lookAt[0] = this.lookAt[0];
this.shadowMapCamera.lookAt[1] = this.lookAt[1];
this.shadowMapCamera.lookAt[2] = this.lookAt[2];
this.shadowMapCamera.rotation[0] = this.rotation[0];
this.shadowMapCamera.rotation[1] = this.rotation[1];
this.shadowMapCamera.rotation[2] = this.rotation[2];
this.shadowMapCamera.updateMatrix()
this.shadowMapCamera.updateWorldMatrix()
// mat4.copy(this.shadowMapCamera.matrix, this.matrix);
// mat4.copy(this.shadowMapCamera.worldMatrix, this.worldMatrix);
// mat4.copy(this.shadowMapCamera.inverseWorldMatrix, this.inverseWorldMatrix);
}
}
}
export default Light;

View File

@@ -1,33 +0,0 @@
export default {
cache: {
},
loadImage (url, callback) {
if (this.cache[url] !== void 0) {
callback( this.cache[url] );
return;
}
var image = new Image();
image.onload = ()=>{
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;
}
}

View File

@@ -1,68 +0,0 @@
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<this.vertices.length/3;i++) {
if (needsUvs) {
this.uvs.push( 0,0 )
}
if (needsNormals) {
this.normals.push( 0,1,0 );
}
}
this.attributes['index'] = new ArrayBuffer(this.gl, new Uint16Array(this.indices), 1, true);
this.attributes['position'] = new ArrayBuffer(this.gl, new Float32Array(this.vertices), 3, false);
this.attributes['normal'] = new ArrayBuffer(this.gl, new Float32Array(this.normals), 3, false);
this.attributes['uv'] = new ArrayBuffer(this.gl, new Float32Array(this.uvs), 2, false);
// this.computeBoundingSphere();
this.options.onLoaded()
}
}
export default ObjGeometryBuffer;

View File

@@ -3,16 +3,6 @@ import * as mat3 from './glMatrix/mat3';
import * as quat from './glMatrix/quat'; import * as quat from './glMatrix/quat';
import * as vec3 from './glMatrix/vec3'; import * as vec3 from './glMatrix/vec3';
// var objects = []
// function needsUpdateLoop() {
// requestAnimationFrame(needsUpdateLoop);
// for (let i=0; i<objects.length; i++) {
// objects[i].needsUpdate = true;
// }
// }
// needsUpdateLoop();
class Object3d { class Object3d {
@@ -94,12 +84,8 @@ class Object3d {
needsUpdate = true; needsUpdate = true;
} }
//update once per frame
//TODO: use Raf
// if (needsUpdate) {
this.updateMatrix(); this.updateMatrix();
this.updateWorldMatrix(); this.updateWorldMatrix();
// }
} }
@@ -130,40 +116,26 @@ class Object3d {
this.up this.up
); );
// var _rotMat4 = mat4.create();
// mat4.multiply(_rotMat4, _rotMat4, this._lookAtMat4);
// mat4.getRotation( this._quaternion, _rotMat4);
// mat4.identity(this._invLookatMat4);
mat4.invert(this.matrix, this.matrix); mat4.invert(this.matrix, this.matrix);
// mat4.copy(this._rotationMat4, this._invLookatMat4);
mat4.scale(this.matrix, this.matrix, this.scale); mat4.scale(this.matrix, this.matrix, this.scale);
} }
else { else {
mat4.scale(this.matrix, this.matrix, this.scale); mat4.scale(this.matrix, this.matrix, this.scale);
mat4.multiply(this.matrix, this.matrix, this._rotationMat4); mat4.multiply(this.matrix, this.matrix, this._rotationMat4);
} }
} }
updateWorldMatrix() { updateWorldMatrix() {
if (this.parent) { if (this.parent) {
// mat4.multiply(this.worldMatrix, this.matrix, this.parent.worldMatrix);
mat4.multiply(this.worldMatrix, this.parent.worldMatrix, this.matrix ); mat4.multiply(this.worldMatrix, this.parent.worldMatrix, this.matrix );
} }
else{ else{
this.worldMatrix = this.matrix; this.worldMatrix = this.matrix;
} }
mat4.invert(this.inverseWorldMatrix, this.worldMatrix); mat4.invert(this.inverseWorldMatrix, this.worldMatrix);
} }
} }

View File

@@ -1,117 +0,0 @@
import Loader from './Loader';
import Mesh from './Mesh';
import Material from './Material';
import Texture from './Texture';
import GeometryBuffer from './GeometryBuffer';
import FrameBuffer from './FrameBuffer';
import particleVertexShader from './shaders/particle-vs.glsl';
import particleFragmentShader from './shaders/particle-fs.glsl';
class ParticleSystem extends Mesh {
constructor(gl, options) {
super();
this.gl = gl;
options = Object.assign({}, {
width: 10,
height: 10,
depth: 10,
map: null,
count: 100
}, options);
this.count = options.count;
this.width = options.width;
this.heigth = options.heigth;
this.depth = options.depth;
this.material = new Material(this.gl, {
blend: true,
map: options.map,
vertexShader: particleVertexShader,
fragmentShader: particleFragmentShader,
});
// this.material.map = this.texture;
this.indices = []
this.vertices = []
this.normals = []
this.colors = []
this.uvs = []
this.vertexIndices = [];
this.particleIndices = [];
var index = 0;
var particleIndex = 0;
for ( var i = 0, l = this.count; i<l; i++) {
this.vertices.push( Math.random() * this.width - (this.width/2) );
this.vertices.push( Math.random() * this.heigth - (this.heigth/2) );
this.vertices.push( Math.random() * this.depth - (this.depth/2) );
this.normals.push(0);
this.normals.push(1);
this.normals.push(1);
this.colors.push(1);
this.colors.push(1);
this.colors.push(1);
this.vertexIndices.push(index);
this.particleIndices.push(particleIndex);
index++;
if(index > 3){
index = 0;
particleIndex++;
}
}
for (let m=0,n=0;n<this.count;m+=6,n+=4) {
this.indices.push(n+0);
this.indices.push(n+2);
this.indices.push(n+1);
this.indices.push(n+2);
this.indices.push(n+3);
this.indices.push(n+1);
this.uvs.push(0);
this.uvs.push(1);
this.uvs.push(1);
this.uvs.push(1);
this.uvs.push(0);
this.uvs.push(0);
this.uvs.push(1);
this.uvs.push(0);
}
this.geometry = new GeometryBuffer(this.gl, this.count);
this.geometry.addAttribute( 'index', new Uint16Array( this.indices ), 1 );
this.geometry.addAttribute( 'position', new Float32Array( this.vertices ), 3 );
this.geometry.addAttribute( 'color', new Float32Array( this.colors ), 3 );
this.geometry.addAttribute( 'normal', new Float32Array( this.normals ), 3 );
this.geometry.addAttribute( 'uv', new Float32Array( this.uvs ), 2,'ParticleSystem' );
this.geometry.addAttribute( 'particleIndex', new Float32Array( this.particleIndices ), 1 );
this.geometry.addAttribute( 'vertexIndex', new Float32Array( this.vertexIndices ), 1 );
this.geometry.length = this.vertexIndices.length;
}
}
export default ParticleSystem;

View File

@@ -1,331 +0,0 @@
// 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 <exposure> 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;
};

View File

@@ -1,114 +0,0 @@
import {Light} from 'beam'
import {Container} from 'beam'
import {vec3, mat4} from 'beam'
var objects = []
function needsUpdateLoop() {
requestAnimationFrame(needsUpdateLoop);
for (let i=0; i<objects.length; i++) {
objects[i]._needsUpdate = true;
}
}
needsUpdateLoop();
class Scene extends Container {
constructor() {
super();
this.lights = [];
this.defines = {}
this.uniforms = {
lightAngleCos: [],
lightColor: [],
lightDecay: [],
lightDirection: [],
lightDistance: [],
lightExponent: [],
lightPosition: [],
lightPenumbraCos: [],
};
//used to overide materials on all objects in the scene by the gven material
this.overrideMaterial = null;
//gl-matrix used typed arrays which are generaly faster but slower on creation time
//so we create them once and reuse them on each frame
this._lightColor = vec3.create();
this._lightPosition = vec3.create();
this._lightDirection = vec3.create();
this._needsUpdate = true;
objects.push(this)
}
add(obj) {
if (obj instanceof Light) {
this.lights.push( obj );
}
else {
super.add(obj)
}
}
render(camera) {
if(this._needsUpdate){
this.uniforms.lightAngleCos = []
this.uniforms.lightColor = []
this.uniforms.lightDecay = []
this.uniforms.lightDirection = []
this.uniforms.lightDistance = []
this.uniforms.lightExponent = []
this.uniforms.lightPosition = []
this.uniforms.lightPenumbraCos = []
//build light uniforms
for (let i=0; i<this.lights.length; i++) {
this.lights[i].update();
this.uniforms.lightAngleCos.push( Math.cos(this.lights[i].angle) )
this.uniforms.lightDecay.push(this.lights[i].decay);
this.uniforms.lightDistance.push(this.lights[i].distance)
this.uniforms.lightExponent.push(this.lights[i].exponent)
this.uniforms.lightPenumbraCos.push(Math.cos( this.lights[i].angle * ( 1 - this.lights[i].penumbra ) ) );
//compute light color from color and intensity
vec3.copy(this._lightColor, this.lights[i].color);
vec3.scale(this._lightColor, this._lightColor, this.lights[i].intensity)
this.uniforms.lightColor.push(this._lightColor[0],this._lightColor[1],this._lightColor[2]);
//retrieve light world position
vec3.set(this._lightPosition, this.lights[i].worldMatrix[12], this.lights[i].worldMatrix[13], this.lights[i].worldMatrix[14])
this.uniforms.lightPosition.push(this._lightPosition[0],this._lightPosition[1],this._lightPosition[2]);
//retrieve light world direction
vec3.copy( this._lightDirection, this._lightPosition )
vec3.subtract(this._lightDirection, this._lightDirection, this.lights[i].lookAt);
vec3.normalize(this._lightDirection, this._lightDirection);
this.uniforms.lightDirection.push(this._lightDirection[0],this._lightDirection[1],this._lightDirection[2]);
}
}
this.defines.NUM_LIGHTS = this.lights.length;
// this.uniforms = Object.assign({},uniforms, this.uniforms);
this._needsUpdate = false;
super.render(camera, this);
}
}
export default Scene;

View File

@@ -1,35 +0,0 @@
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;

View File

@@ -1,5 +1,4 @@
import uuid from './utils/uuid'; import uuid from './utils/uuid';
import getFilter from './utils/getFilter'; import getFilter from './utils/getFilter';
import isPowerOf2 from './utils/isPowerOf2'; import isPowerOf2 from './utils/isPowerOf2';
@@ -9,12 +8,10 @@ class Texture {
constructor(gl, options) { constructor(gl, options) {
if (!gl) { if (!gl) {
return; return;
} }
this.options = Object.assign({}, { this.options = Object.assign({}, {
format: gl.RGBA, format: gl.RGBA,
type: gl.UNSIGNED_BYTE, type: gl.UNSIGNED_BYTE,

View File

@@ -1,32 +0,0 @@
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;

View File

@@ -1,68 +0,0 @@
/* 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;
// }

View File

@@ -1,237 +0,0 @@
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;

View File

@@ -1,253 +0,0 @@
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:
* <pre>
* [a, b,
* c, d,
* tx,ty]
* </pre>
* This is a short form for the 3x3 matrix:
* <pre>
* [a, b, 0
* c, d, 0
* tx,ty,1]
* </pre>
* 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;

View File

@@ -1,478 +0,0 @@
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;

View File

@@ -1,908 +0,0 @@
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;

View File

@@ -1,531 +0,0 @@
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;

View File

@@ -1,538 +0,0 @@
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;

View File

@@ -1,562 +0,0 @@
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;

View File

@@ -1,526 +0,0 @@
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;

View File

@@ -1,3 +1,13 @@
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 ArrayBuffer} from './ArrayBuffer'; export {default as ArrayBuffer} from './ArrayBuffer';
export {default as Program} from './Program'; export {default as Program} from './Program';
export {default as Material} from './Material'; export {default as Material} from './Material';
@@ -8,20 +18,6 @@ export {default as Renderer} from './Renderer';
export {default as Camera} from './Camera'; export {default as Camera} from './Camera';
export {default as Object3d} from './Object3d'; 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 GeometryBuffer} from './GeometryBuffer';
export {default as PlaneGeometryBuffer} from './PlaneGeometryBuffer'; export {default as PlaneGeometryBuffer} from './PlaneGeometryBuffer';
export {default as SphereGeometryBuffer} from './SphereGeometryBuffer'; export {default as SphereGeometryBuffer} from './SphereGeometryBuffer';

View File

@@ -1,11 +0,0 @@
precision highp float;
varying vec2 vUv;
void main(void) {
vec4 outColor = vec4(1., 0., 0., 1.0);
gl_FragColor = outColor;
}

View File

@@ -1,62 +0,0 @@
// 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);
}

View File

@@ -1,135 +0,0 @@
// 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 );
}

View File

@@ -1,38 +0,0 @@
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 );
}

View File

@@ -1,5 +1,3 @@
export default function isPowerOf2(value) { export default function isPowerOf2(value) {
return (value & (value - 1)) == 0; return (value & (value - 1)) == 0;
} }

View File

@@ -4,28 +4,17 @@ var uuid = new Array( 36 );
var rnd = 0, r; var rnd = 0, r;
export default function generateUUID() { export default function generateUUID() {
for ( var i = 0; i < 36; i ++ ) { for ( var i = 0; i < 36; i ++ ) {
if ( i === 8 || i === 13 || i === 18 || i === 23 ) { if ( i === 8 || i === 13 || i === 18 || i === 23 ) {
uuid[ i ] = '-'; uuid[ i ] = '-';
} else if ( i === 14 ) { } else if ( i === 14 ) {
uuid[ i ] = '4'; uuid[ i ] = '4';
} else { } else {
if ( rnd <= 0x02 ) rnd = 0x2000000 + ( Math.random() * 0x1000000 ) | 0; if ( rnd <= 0x02 ) rnd = 0x2000000 + ( Math.random() * 0x1000000 ) | 0;
r = rnd & 0xf; r = rnd & 0xf;
rnd = rnd >> 4; rnd = rnd >> 4;
uuid[ i ] = chars[ ( i === 19 ) ? ( r & 0x3 ) | 0x8 : r ]; uuid[ i ] = chars[ ( i === 19 ) ? ( r & 0x3 ) | 0x8 : r ];
} }
} }
return uuid.join( '' ); return uuid.join( '' );
}
};

View File

@@ -1,396 +0,0 @@
/*
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: { '<mesh_name>': 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&#39;s Vertex Normals
* normalBuffer.itemSize |set to 3 items
* normalBuffer.numItems |the total number of vertex normals
* |
* **textureBuffer** |contains the model&#39;s Texture Coordinates
* textureBuffer.itemSize |set to 2 items
* textureBuffer.numItems |the number of texture coordinates
* |
* **vertexBuffer** |contains the model&#39;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;

View File

@@ -54,7 +54,6 @@ void main(void) {
outColor = diffuseColor * vec3(NdotL) + diffuseColor * ambient * (1.-NdotL); outColor = diffuseColor * vec3(NdotL) + diffuseColor * ambient * (1.-NdotL);
// outColor = pow(outColor, vec3(1.0 / 2.2));
gl_FragColor = vec4( outColor, 1. ); gl_FragColor = vec4( outColor, 1. );
} }
` `

View File

@@ -9,6 +9,7 @@ uniform mat4 uMVMatrix;
uniform mat4 uMMatrix; uniform mat4 uMMatrix;
uniform mat4 uPMatrix; uniform mat4 uPMatrix;
uniform mat4 uNormalMatrix; uniform mat4 uNormalMatrix;
uniform float uCameraOffsetY;
varying vec2 vUv; varying vec2 vUv;
varying vec3 vNormal; varying vec3 vNormal;
@@ -16,8 +17,10 @@ varying vec3 vPos;
void main(void) { void main(void) {
vUv = uv; vUv = uv;
vNormal = (vec4(normal, 0.) * uNormalMatrix).rgb; vNormal = (uNormalMatrix * vec4(normal, 1.)).rgb;
vPos = (vec4(vPos, 1.) * uMMatrix).rgb; vPos = (uMMatrix * vec4(position, 1.)).rgb;
gl_Position = uPMatrix * uMVMatrix * vec4( position, 1.0 ); gl_Position = uPMatrix * uMVMatrix * vec4( position, 1.0 );
gl_Position[1] += uCameraOffsetY * gl_Position.w;
} }
` `

View File

@@ -1,22 +1,15 @@
import { Renderer } from './beam' import { Renderer } from './beam'
import { Camera } from './beam' import { Camera } from './beam'
import { vec2, vec3, mat4 } from './beam' import { vec2, vec3, mat4 } from './beam'
import { Container, Mesh, Material, Texture, SphereGeometryBuffer } from './beam' import { Container, Mesh, Material, Texture, SphereGeometryBuffer, PlaneGeometryBuffer } from './beam'
import settings from './settings'
// Shaders in strings // GLSL shaders as strings
import GlobeVS from './globe-vs' import GlobeVS from './globe-vs'
import GlobeFS from './globe-fs' import GlobeFS from './globe-fs'
const hexToRgb = hex => { const FOV = 1;
const 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]
}
/** get 3D position on a sphere from longitute lattitude */
const lonLatToVector3 = (lng, lat) => { const lonLatToVector3 = (lng, lat) => {
const phi = (90 - lat) * (Math.PI / 180) const phi = (90 - lat) * (Math.PI / 180)
const theta = (lng + 180) * (Math.PI / 180) const theta = (lng + 180) * (Math.PI / 180)
@@ -27,19 +20,20 @@ const lonLatToVector3 = (lng, lat) => {
} }
class WebglGlobe { class WebglGlobe {
// Constructor // Constructor
constructor (options) { constructor (options) {
// Camera position cache
this.cameraX = 0
this.cameraY = 0
this.cameraZ = 0
this.$el = options.el//the Dom reference node
this.options = options this.options = options
this.options.autoRotationSpeed = this.options.autoRotationSpeed || 0 this.options.autoRotationSpeed = this.options.autoRotationSpeed || 0
this.options.scrollSmoothing = this.options.scrollSmoothing || 0.5 // smooth the globe position to avoid janks on scroll(lower==smoother)
this.options.cameraDistance = this.options.cameraDistance || 1 //a multiplier to move camera backward or forward
this.referenceHeight = 1;//used to set camera distance from globe where referenceHeight == window height
this._canUpdate = false
this.cities = options.markers//list of cities with their options
this.$el = options.el
this.cities = options.markers
let gl let gl
let canvas = document.createElement('canvas') let canvas = document.createElement('canvas')
try { gl = canvas.getContext('webgl') } try { gl = canvas.getContext('webgl') }
@@ -51,21 +45,44 @@ class WebglGlobe {
if (this.supportWebgl) { if (this.supportWebgl) {
this.buildWebglScene() this.buildWebglScene()
this.resize() this.resize()
// this.initPointer()
} }
} }
// Build // Build
buildWebglScene () { buildWebglScene () {
this.renderer = new Renderer({
alpha: this.alpha,
antialias: window.innerWidth < 768 ? true : false,// this.antialias,
})
this.$el.appendChild(this.renderer.canvas)
// Load texture this.renderer = new Renderer({
//to allow transparent background on webgl canvas
alpha: true,
//only enable antialiasing if screen is small with no retina(for performances reasons)
antialias: window.innerWidth < 768 || !window.devicePixelRatio == 1 ? true : false,
})
// we put the canvas at the end of body tag as 'position:fixed'
// this is to avoid having a too big canvas if the globe needs to be very large:
// so instead we move the globe as we scroll
this.renderer.canvas.style.position = 'fixed'
this.renderer.canvas.style.top = 0
this.renderer.canvas.style.left = 0
this.renderer.canvas.style.pointerEvents = 'none'
this.renderer.canvas.style.zIndex = 100
document.body.appendChild(this.renderer.canvas)
// The markers DOM nodes wrapper
// this wrapper is added just next to the canvas, at the end of body tag
this.$markerWrapper = document.createElement('div')
this.$markerWrapper.classList.add('markerWrapper')
this.$markerWrapper.style.position = 'fixed'
this.$markerWrapper.style.top = 0
this.$markerWrapper.style.left = 0
this.$markerWrapper.style.pointerEvents = 'none'
this.$markerWrapper.style.zIndex = 101
document.body.appendChild(this.$markerWrapper)
// Load worldmap texture
this.texture = Texture.fromUrl(this.renderer.gl, this.options.texture, { this.texture = Texture.fromUrl(this.renderer.gl, this.options.texture, {
loaded: () => { loaded: () => {
//TODO: use only one RAF if possible
requestAnimationFrame(() => { requestAnimationFrame(() => {
requestAnimationFrame(() => { requestAnimationFrame(() => {
this.imageLoaded = true this.imageLoaded = true
@@ -78,64 +95,67 @@ class WebglGlobe {
// Setup camera // Setup camera
this.camera = new Camera({ this.camera = new Camera({
fov: settings.fov, fov: 1,
near: 1, near: 0.1,
far: settings.cameraFar, far: 1000,
type: 'perspective', type: 'perspective',
orbitControl: true, orbitControl: true,
firstPerson: false, firstPerson: false,
lookAt: [0,0,0], lookAt: [0,0,0],
position: [0,0, (this.options.cameraDistance) / 2 / Math.tan(Math.PI * settings.fov / 360)], position: [0,0,0],
pointerParent: this.$el pointerParent: this.$el
}) })
this.camera.lookAt = vec3.create() this.camera.lookAt = vec3.create()
this.inverseViewProjectionMatrix = mat4.create()
/**
* used to compute screen position of markers,
* to move the corresponding DOM nodes
*/
this.viewProjectionMatrix = mat4.create() this.viewProjectionMatrix = mat4.create()
this.cameraDirection = vec3.create()
this.cameraPosition = vec3.create() this.cameraPosition = vec3.create()
this.globeMesh = new Mesh() this.globeMesh = new Mesh()
this.globeMesh.material = new Material(this.renderer.gl, { this.globeMesh.material = new Material(this.renderer.gl, {
uniforms: { uniforms: {
tInput: this.texture tInput: this.texture,
uCameraOffsetY: 0,
}, },
vertexShader: GlobeVS, vertexShader: GlobeVS,
fragmentShader: GlobeFS, fragmentShader: GlobeFS,
// depthTest: true
}) })
this.globeMesh.geometry = new SphereGeometryBuffer(this.renderer.gl, { this.globeMesh.geometry = new SphereGeometryBuffer(this.renderer.gl, {
radius: 1, radius: this.referenceHeight/2,
widthSegments: 100, heightSegments: 100 widthSegments: 100, heightSegments: 100
}) })
this.scene.add(this.globeMesh) this.scene.add(this.globeMesh)
// this.refPlane = new Mesh()
// this.refPlane.material = new Material(this.renderer.gl, {
// uniforms: {
// color: [0,1,0]
// }
// })
// this.refPlane.geometry = new PlaneGeometryBuffer(this.renderer.gl, {
// width: this.referenceHeight, height: this.referenceHeight
// })
// this.scene.add(this.refPlane)
/**
* Create DOM nodes for markers and 3D positions
*/
this.markers = [] this.markers = []
let markers = this.cities let markers = this.cities
// Instance all markers // Instance all markers
for (let i = 0; i < markers.length; i++) { for (let i = 0; i < markers.length; i++) {
let markerMesh = new Mesh();
markerMesh.material = new Material(this.renderer.gl, {
blend: true,
uniforms: {
color: hexToRgb('#FF6C89'),
alpha: 0,
}
})
markerMesh.geometry = new SphereGeometryBuffer(this.renderer.gl, {
radius: 0.01,
widthSegments: 10, heightSegments: 10
})
// Position marker // Position marker
let p = lonLatToVector3(markers[i].lng, markers[i].lat) let p = lonLatToVector3(markers[i].lng, markers[i].lat)
markerMesh.position[0] = p[0]
markerMesh.position[1] = p[1]
markerMesh.position[2] = p[2]
this.scene.add(markerMesh)
// Wrap marker in link // Wrap marker in link
let el = document.createElement('a') let el = document.createElement('a')
el.style.pointerEvents = 'auto'
el.setAttribute('href', '/location/' + markers[i].countrySlug + '/' + markers[i].slug) el.setAttribute('href', '/location/' + markers[i].countrySlug + '/' + markers[i].slug)
el.setAttribute('sapper-noscroll', '') el.setAttribute('sapper-noscroll', '')
if (markers[i].className) el.classList.add( markers[i].className ) if (markers[i].className) el.classList.add( markers[i].className )
@@ -170,9 +190,9 @@ class WebglGlobe {
el.addEventListener('animationend', () => el.classList.remove('hover')) el.addEventListener('animationend', () => el.classList.remove('hover'))
// Append marker to HTML // Append marker to HTML
this.$el.appendChild(el) this.$markerWrapper.appendChild(el)
this.markers.push({ this.markers.push({
mesh: markerMesh,
el: el, el: el,
position: p, position: p,
screenPosition: [0,0] screenPosition: [0,0]
@@ -182,117 +202,99 @@ class WebglGlobe {
// Resize method // Resize method
resize () { resize () {
this.width = this.$el.clientWidth
this.height = this.$el.clientHeight
// console.log('GLOBE RESIZE', this.width, this.height)
settings.resolution[0] = this.width //* settings.devicePixelRatio
settings.resolution[1] = this.height //* settings.devicePixelRatio
if (!this.supportWebgl) { if (!this.supportWebgl) {
return return
} }
this.renderer.setPixelRatio(1)//window.innerWidth < 768 ? 1 : settings.devicePixelRatio)
this.renderer.resize(settings.resolution[0], settings.resolution[1]) this.width = window ? window.innerWidth : 0
this.camera.aspect = settings.resolution[0] / settings.resolution[1] this.height = window ? window.innerHeight : 0
//remove retina on small screen(aka mobile) to boost perfs
this.renderer.setPixelRatio( window.innerWidth < 768 ? 1 : window.devicePixelRatio)
this.renderer.resize(this.width , this.height)
//update camera aspect ratio
this.camera.aspect = this.width / this.height
this.camera.updateProjectionMatrix() this.camera.updateProjectionMatrix()
this.camera.lookAt[0] = 0 //at which distance to put the camera when rotating arounf the globe
this.camera.lookAt[1] = 0 this.camera._cameraDistance = (this.referenceHeight * this.options.cameraDistance) / 2 / Math.tan(Math.PI * FOV / 360);
this.camera.lookAt[2] = 0 this.camera.update(true)
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) * When markers are behind the globe, clamp their position
vec3.subtract(this.cameraDirection, this.cameraDirection, this.cameraPosition) * to this size to make them move along the circle edge
vec3.normalize(this.cameraDirection, this.cameraDirection) */
mat4.copy(this.viewProjectionMatrix, this.camera.projectionMatrix) this.circleScreenSize = (this.height / 2) * (1 / this.options.cameraDistance);
mat4.multiply(this.viewProjectionMatrix, this.viewProjectionMatrix, this.camera.inverseWorldMatrix) }
let refPos = vec3.create() /**
vec3.set(refPos, 0, 1, 0) * As the camera rotates arount the globe, we cant simply move the Y position of the camera or the globe
vec3.transformMat4(refPos, refPos, this.viewProjectionMatrix) * Instead, we move the globe vertex inside the vertex shadder after compute the project on screen, so we pass the 'scroll' position to a uniform
let refx = ((refPos[0] + 1) / 2) * this.width */
let refy = (1. - (refPos[1] + 1) / 2) * this.height updateCameraPos(y) {
y *= 2;
if (this.globeMesh.material.uniforms.uCameraOffsetY) {
this.globeMesh.material.uniforms.uCameraOffsetY.value += ( y - this.globeMesh.material.uniforms.uCameraOffsetY.value ) * this.options.scrollSmoothing
}
}
let dir2 = vec2.create() /**
vec2.set(dir2, refx, refy) * Flag to stop rendering the webgl if the globe isnt visible
let center2 = vec2.create() * This helps saving perfs and battery
vec2.set(center2, this.width / 2, this.height / 2) */
let dir2d2 = vec2.clone(dir2, dir2) enable() {
vec2.subtract(dir2d2, dir2d2, center2) this._canUpdate = true
this.circleScreenSize = vec2.length(dir2d2) * 1.04 }
disable() {
this._canUpdate = false
} }
// Update // Update
update () { update () {
if (!this.supportWebgl || !this._canUpdate || !this.imageLoaded) {
if (!this.supportWebgl) {
return return
} }
// Manually call this as we prevent the camera from update between passes //compute the camera view-projection matrix to use it on the markers
this.camera.update() this.camera.update()
vec3.set(this.cameraPosition, this.camera.worldMatrix[12], this.camera.worldMatrix[13], this.camera.worldMatrix[14]) 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.copy(this.viewProjectionMatrix, this.camera.projectionMatrix)
mat4.multiply(this.viewProjectionMatrix, this.viewProjectionMatrix, this.camera.inverseWorldMatrix) mat4.multiply(this.viewProjectionMatrix, this.viewProjectionMatrix, this.camera.inverseWorldMatrix)
mat4.invert(this.inverseViewProjectionMatrix, this.viewProjectionMatrix)
// let needsUpdate = false //Auto rotate the globe
// if (this.cameraX != this.camera.worldMatrix[12] || this.globeMesh.rotation[1] = this.options.autoRotationSpeed
// this.cameraY != this.camera.worldMatrix[13] || this.globeMesh.updateMatrix()
// this.cameraZ != this.camera.worldMatrix[14] this.globeMesh.updateWorldMatrix()
// ) {
// this.cameraX = this.camera.worldMatrix[12]
// this.cameraY = this.camera.worldMatrix[13]
// this.cameraZ = this.camera.worldMatrix[14]
// needsUpdate = true
// }
let needsUpdate = true;
if (!needsUpdate && this.imageLoaded) {
return
}
this.globeMesh.rotation[0] = 0
this.globeMesh.rotation[1] += this.options.autoRotationSpeed;
this.globeMesh.rotation[2] = 0
let screenPos = vec3.create() let screenPos = vec3.create()
this.markers.forEach((marker, i) => { this.markers.forEach((marker, i) => {
//get marker 3D position and project it on screen to get 2D position
vec3.set(screenPos, marker.position[0], marker.position[1], marker.position[2]) vec3.set(screenPos, marker.position[0], marker.position[1], marker.position[2])
vec3.transformMat4(screenPos, screenPos, this.globeMesh.worldMatrix) vec3.transformMat4(screenPos, screenPos, this.globeMesh.worldMatrix)
vec3.transformMat4(screenPos, screenPos, this.viewProjectionMatrix) vec3.transformMat4(screenPos, screenPos, this.viewProjectionMatrix)
//marker 2D screen position (starting from top left corner of screen)
let x = ((screenPos[0] + 1) / 2) * this.width let x = ((screenPos[0] + 1) / 2) * this.width
let y = (1. - (screenPos[1] + 1) / 2) * this.height let y = (1. - (screenPos[1] + 1) / 2) * this.height
//compute marker Normal
let N = vec3.create() let N = vec3.create()
vec3.set(N, marker.position[0], marker.position[1], marker.position[2]) vec3.set(N, marker.position[0], marker.position[1], marker.position[2])
vec3.transformMat4(N, N, this.globeMesh.worldMatrix) vec3.transformMat4(N, N, this.globeMesh.worldMatrix)
vec3.normalize(N, N) vec3.normalize(N, N)
//compute view vector (camera direction)
let V = vec3.create() let V = vec3.create()
vec3.set(V, marker.position[0], marker.position[1], marker.position[2]) vec3.set(V, marker.position[0], marker.position[1], marker.position[2])
vec3.subtract(V, V, this.cameraPosition) vec3.subtract(V, V, this.cameraPosition)
vec3.normalize(V, V) vec3.normalize(V, V)
//behind //the marker is behind the globe: clamp it to the globe edge
if (vec3.dot(V, N) * -1 < 0) { if (vec3.dot(V, N) * -1 < 0) {
let dir = vec2.create() let dir = vec2.create()
vec2.set(dir, x, y) vec2.set(dir, x, y)
@@ -306,15 +308,15 @@ class WebglGlobe {
marker.el.style.transform = `translate(${dir2d[0]}px, ${dir2d[1]}px) translateZ(0)` marker.el.style.transform = `translate(${dir2d[0]}px, ${dir2d[1]}px) translateZ(0)`
marker.el.classList.remove('is-active') marker.el.classList.remove('is-active')
} }
//marker is in front of the globe; update 2D position
else { 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.style.transform = `translate(${x}px, ${y}px) translateZ(0)`
marker.el.classList.add('is-active') marker.el.classList.add('is-active')
} }
// marker.el.style.opacity = 1.
}) })
this.renderer.clearColor(0,0,0,0) //render webgl frame
this.renderer.clearColor(0,0,0,0)//[RGBA] alpha is set to 0 to have a transparent background on the webgl
this.renderer.clear() this.renderer.clear()
this.renderer.render(this.scene, this.camera) this.renderer.render(this.scene, this.camera)
} }

View File

@@ -1,12 +0,0 @@
var params = {
debug: true,
fov: 45,
devicePixelRatio: window.devicePixelRatio,
resolution: [window.innerWidth, window.innerHeight],
focalLength: 2.415,
cameraFar: 1000,
gammaCorrection: true,
}
export default params;

View File

@@ -1,47 +0,0 @@
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

View File

@@ -1,14 +1,38 @@
<script> <script>
import { onMount } from 'svelte' import { onMount } from 'svelte'
import { locations } from 'utils/store' import { locations } from 'utils/store'
import ScrollOut from 'scroll-out'
function getPosition (node, scope) {
var root = scope || document;
var offsetTop = node.offsetTop;
var offsetLeft = node.offsetLeft;
while (node && node.offsetParent && node.offsetParent != document && node !== root && root !== node.offsetParent ) {
offsetTop += node.offsetParent.offsetTop;
offsetLeft += node.offsetParent.offsetLeft;
node = node.offsetParent;
}
return {
top: offsetTop,
left: offsetLeft
};
}
// Props // Props
export let type = '' // export let type = ''
let scope let scope
let globe let globe
let containerTop = 0
let containerHeight = 0
let winHeight = window ? window.innerHeight : 0
// Functions
const resize = () => { const resize = () => {
winHeight = window ? window.innerHeight : 0
if (scope) {
containerTop = getPosition( scope ).top
containerHeight = scope.clientHeight
}
globe.resize() globe.resize()
globe.update() globe.update()
} }
@@ -17,22 +41,41 @@
globe.update() globe.update()
} }
const onScroll = (e)=> {
let scrollDiff = (containerTop + window.innerHeight + (containerHeight - window.innerHeight) /2 ) - document.documentElement.scrollTop
let scrollRatio = 1 - ( scrollDiff / window.innerHeight )
globe && globe.updateCameraPos( scrollRatio )
}
/* /*
** Run code when mounted ** Run code when mounted
*/ */
onMount(async () => { onMount(async () => {
// For browser only
const globeScroll = ScrollOut({
once: false,
targets: scope,
// threshold: 1,
onShown: () => {
globe.enable()
},
onHidden: () => {
globe.disable()
},
})
let InteractiveGlobe
if (process.browser) { if (process.browser) {
// Import libraries and code // Import libraries and code
let Globe await import('globe/index').then(module => InteractiveGlobe = module.default)
await import('globe').then(module => Globe = module.default)
// Init the globe from library // Init the globe from library
globe = new Globe({ globe = new InteractiveGlobe({
el: scope, el: scope,
cameraDistance: 1.5,
autoRotationSpeed: -0.01, autoRotationSpeed: -0.01,
texture: `/img/globe/map-${window.innerWidth >= 992 ? '4k' : '2k'}.png`, scrollSmoothing: 0.5,
texture: `/img/globe/map-${window.innerWidth > 1440 && window.devicePixelRatio > 1 ? '4k' : '2k'}.png`,
markers: [...$locations.map(location => { markers: [...$locations.map(location => {
return { return {
name: location.name, name: location.name,
@@ -44,7 +87,6 @@
className: location.slug === 'marseille' ? 'is-left' : '', className: location.slug === 'marseille' ? 'is-left' : '',
} }
})], })],
cameraDistance: 3,
onLinkClicked: () => {} onLinkClicked: () => {}
}) })
@@ -55,12 +97,14 @@
}) })
</script> </script>
<svelte:window on:resize={resize} /> <svelte:window on:resize={resize} on:scroll={onScroll} />
{#if type === 'part'} <!-- {#if type === 'part'}
<div class="globe__cut"> <div class="globe__cut">
<div class="globe" bind:this={scope} /> <div class="globe" bind:this={scope} />
</div> </div>
{:else} {:else}
<div class="globe" bind:this={scope} /> <div class="globe" bind:this={scope} />
{/if} {/if} -->
<div class="globe" bind:this={scope} />

View File

@@ -8,7 +8,6 @@
// Props and variables // Props and variables
export let photo export let photo
export let index export let index
export let layout = 'list'
let scope let scope
// Default size for the image // Default size for the image
@@ -54,10 +53,10 @@
<source media="(min-width: 768px)" data-srcset={getThumbnail(private_hash, 992)}> <source media="(min-width: 768px)" data-srcset={getThumbnail(private_hash, 992)}>
<source media="(min-width: 500px)" data-srcset={getThumbnail(private_hash, 650)}> <source media="(min-width: 500px)" data-srcset={getThumbnail(private_hash, 650)}>
<source media="(min-width: 300px)" data-srcset={getThumbnail(private_hash, 400)}> <source media="(min-width: 300px)" data-srcset={getThumbnail(private_hash, 400)}>
<img src={getThumbnail(private_hash, 900)} <img src="data:image/png;base64,R0lGODlhAQABAAD/ACwAAAAAAQABAAACADs="
width={defaultWidth} height={defaultHeight} width={defaultWidth} height={defaultHeight}
alt={imgAlt} alt={imgAlt}
class:lazyload={layout === 'list'} class="lazyload"
/> />
</picture> </picture>
</a> </a>

View File

@@ -5,7 +5,6 @@
import { getThumbnail, formatDate } from 'utils/functions' import { getThumbnail, formatDate } from 'utils/functions'
// Dependencies // Dependencies
import SwipeListener from 'swipe-listener' import SwipeListener from 'swipe-listener'
import lazySizes from 'lazysizes'
// Animations // Animations
import { animateIn } from 'animations/Carousel' import { animateIn } from 'animations/Carousel'
// Components // Components
@@ -159,7 +158,7 @@
<source media="(min-width: 800px)" data-srcset={getThumbnail(image.private_hash, 900)}> <source media="(min-width: 800px)" data-srcset={getThumbnail(image.private_hash, 900)}>
<source media="(min-width: 500px)" data-srcset={getThumbnail(image.private_hash, 600)}> <source media="(min-width: 500px)" data-srcset={getThumbnail(image.private_hash, 600)}>
<source media="(min-width: 300px)" data-srcset={getThumbnail(image.private_hash, 400)}> <source media="(min-width: 300px)" data-srcset={getThumbnail(image.private_hash, 400)}>
<img src={getThumbnail(image.private_hash, 900)} <img src="data:image/png;base64,R0lGODlhAQABAAD/ACwAAAAAAQABAAACADs="
alt="{name}, {location.name}, {location.country.name}" alt="{name}, {location.name}, {location.country.name}"
width={defaultWidth} height={defaultHeight} width={defaultWidth} height={defaultHeight}
class:lazyload={ class:lazyload={

View File

@@ -26,7 +26,8 @@
</div> </div>
{/if} {/if}
<section class="page"> <main class="housesof" class:is-transitioning={!$pageReady}>
<section class="page">
<div class="wrap"> <div class="wrap">
<div class="page__top"> <div class="page__top">
<a href="/" class="button-control button-control--pink dir-left"> <a href="/" class="button-control button-control--pink dir-left">
@@ -44,4 +45,5 @@
</div> </div>
<Footer /> <Footer />
</section> </section>
</main>

View File

@@ -63,7 +63,6 @@
<script> <script>
import { onMount } from 'svelte' import { onMount } from 'svelte'
import { fade } from 'svelte/transition'
import { stores } from '@sapper/app' import { stores } from '@sapper/app'
import { import {
apiEndpoints, apiEndpoints,
@@ -73,11 +72,38 @@
locations, locations,
pageReady pageReady
} from 'utils/store' } from 'utils/store'
// Dependencies
import lazySizes from 'lazysizes'
// Components // Components
import AnalyticsTracker from 'utils/AnalyticsTracker'
import Transition from 'utils/Transition'
// Variables // Variables
const { page } = stores() const { page } = stores()
let AnalyticsTracker
// Settings
lazySizes.cfg.lazyClass = 'lazyload'
/*
** Head stuff
*/
// Preconnect
const preconnect = [
'https://api.housesof.world',
'https://www.googletagmanager.com',
'https://stats.g.doubleclick.net',
'https://www.google-analytics.com',
]
// Preload assets
const preload = {
fonts: [
'/fonts/G-Light.woff2',
'/fonts/G-Regular.woff2',
'/fonts/G-Semibold.woff2',
'/fonts/M-Extralight.woff2',
'/fonts/M-Light.woff2',
]
}
/* /*
@@ -101,12 +127,6 @@
if ($locations) { if ($locations) {
$locations.forEach(loc => loc.country = $countries.find(cont => cont.id === loc.country.id)) $locations.forEach(loc => loc.country = $countries.find(cont => cont.id === loc.country.id))
} }
onMount(async () => {
const gaTracker = await import('utils/AnalyticsTracker')
AnalyticsTracker = gaTracker.default
})
</script> </script>
<style lang="scss" global> <style lang="scss" global>
@@ -115,14 +135,17 @@
<svelte:head> <svelte:head>
<link rel="canonical" href={`https://${$page.host}${$page.path}`} /> <link rel="canonical" href={`https://${$page.host}${$page.path}`} />
{#each preconnect as host}
<link rel="preconnect" href={host} crossorigin>
<link rel="dns-prefetch" href={host}>
{/each}
{#each preload.fonts as font}
<link rel="preload" href={font} as="font" type="font/woff2" crossorigin>
{/each}
</svelte:head> </svelte:head>
<main class="housesof" <slot></slot>
class:is-transitioning={!$pageReady}
in:fade={{ duration: 600 }}
out:fade={{ duration: 600 }}
>
<slot></slot>
</main>
<svelte:component this={AnalyticsTracker} {stores} id={process.env.CONFIG.GA_TRACKER_ID} /> <Transition />
<AnalyticsTracker {stores} id={process.env.CONFIG.GA_TRACKER_ID} />

View File

@@ -5,7 +5,8 @@
site, site,
currentLocation, currentLocation,
currentPhotos, currentPhotos,
pageReady pageReady,
pageAnimation
} from 'utils/store' } from 'utils/store'
// Components // Components
import IconArrow from 'atoms/IconArrow' import IconArrow from 'atoms/IconArrow'
@@ -20,6 +21,7 @@
// Variables // Variables
const { page } = stores() const { page } = stores()
pageAnimation.set(animateIn)
// Reset current location // Reset current location
currentLocation.set() currentLocation.set()
@@ -46,7 +48,7 @@
/> />
</svelte:head> </svelte:head>
<Transition {animateIn}> <main class="housesof" class:is-transitioning={!$pageReady}>
<section class="page explore"> <section class="page explore">
<div class="wrap"> <div class="wrap">
<div class="page__top"> <div class="page__top">
@@ -69,4 +71,4 @@
</section> </section>
<Footer /> <Footer />
</Transition> </main>

View File

@@ -9,12 +9,12 @@
import InteractiveGlobe from 'molecules/InteractiveGlobe' import InteractiveGlobe from 'molecules/InteractiveGlobe'
import Footer from 'organisms/Footer' import Footer from 'organisms/Footer'
import SocialMetas from 'utils/SocialMetas' import SocialMetas from 'utils/SocialMetas'
import Transition from 'utils/Transition'
// Animations // Animations
import { animateIn } from 'animations/page' import { animateIn } from 'animations/page'
// Variables // Variables
const { page } = stores() const { page } = stores()
pageAnimation.set(animateIn)
/* /*
@@ -37,7 +37,7 @@
/> />
</svelte:head> </svelte:head>
<Transition {animateIn}> <main class="housesof" class:is-transitioning={!$pageReady}>
<section class="page"> <section class="page">
<div class="wrap"> <div class="wrap">
<div class="page__top"> <div class="page__top">
@@ -80,4 +80,4 @@
<Footer /> <Footer />
</section> </section>
</Transition> </main>

View File

@@ -29,9 +29,12 @@
site, site,
currentLocation, currentLocation,
currentPhotos, currentPhotos,
pageReady pageReady,
pageAnimation
} from 'utils/store' } from 'utils/store'
import { charsToSpan, smoothScroll } from 'utils/functions' import { charsToSpan, smoothScroll } from 'utils/functions'
// Dependencies
import Lazy from 'svelte-lazy'
// Components // Components
import Button from 'atoms/Button' import Button from 'atoms/Button'
import IconGlobeSmall from 'atoms/IconGlobeSmall' import IconGlobeSmall from 'atoms/IconGlobeSmall'
@@ -42,9 +45,9 @@
import Locations from 'organisms/Locations' import Locations from 'organisms/Locations'
import Footer from 'organisms/Footer' import Footer from 'organisms/Footer'
import SocialMetas from 'utils/SocialMetas' import SocialMetas from 'utils/SocialMetas'
import Transition from 'utils/Transition'
// Animations // Animations
import { animateIn } from 'animations/index' import { animateIn } from 'animations/index'
pageAnimation.set(animateIn)
// Props and Variables // Props and Variables
export let photos = '' export let photos = ''
@@ -75,7 +78,7 @@
/> />
</svelte:head> </svelte:head>
<Transition animateIn={animateIn}> <main class="housesof" class:is-transitioning={!$pageReady}>
<section class="intro"> <section class="intro">
<div class="anim-mask"> <div class="anim-mask">
<div class="anim title-parallax" id="title-houses"> <div class="anim title-parallax" id="title-houses">
@@ -112,7 +115,11 @@
<p>{$site.explore_globe}</p> <p>{$site.explore_globe}</p>
</div> </div>
{#if process.browser}
<Lazy offset={window.innerHeight}>
<InteractiveGlobe /> <InteractiveGlobe />
</Lazy>
{/if}
<div class="anim-mask anim-title"> <div class="anim-mask anim-title">
<h1 class="title-massive title-parallax" id="title-world" aria-label="World"> <h1 class="title-massive title-parallax" id="title-world" aria-label="World">
@@ -124,4 +131,4 @@
</section> </section>
<Footer /> <Footer />
</Transition> </main>

View File

@@ -29,11 +29,10 @@
locations, locations,
currentLocation, currentLocation,
currentPhotos, currentPhotos,
pageReady pageReady,
pageAnimation
} from 'utils/store' } from 'utils/store'
import { formatDate, relativeTime, getThumbnail } from 'utils/functions' import { formatDate, relativeTime, getThumbnail } from 'utils/functions'
// Dependencies
import lazySizes from 'lazysizes'
// Components // Components
import IconGlobe from 'atoms/IconGlobe' import IconGlobe from 'atoms/IconGlobe'
import IconGlobeSmall from 'atoms/IconGlobeSmall' import IconGlobeSmall from 'atoms/IconGlobeSmall'
@@ -51,6 +50,7 @@
// Props and variables // Props and variables
export let photos export let photos
const { page } = stores() const { page } = stores()
pageAnimation.set(animateIn)
let layoutSetting let layoutSetting
let windowWidth let windowWidth
@@ -107,7 +107,7 @@
<svelte:window bind:innerWidth={windowWidth} /> <svelte:window bind:innerWidth={windowWidth} />
<Transition {animateIn}> <main class="housesof" class:is-transitioning={!$pageReady}>
<section class="place"> <section class="place">
<div class="place__title"> <div class="place__title">
<h1 class="title-location title-location--big" aria-label="Houses of {location.name}"> <h1 class="title-location title-location--big" aria-label="Houses of {location.name}">
@@ -146,7 +146,7 @@
</p> </p>
{/if} {/if}
{#if photos} {#if photos.length}
<p class="updated style-caps"> <p class="updated style-caps">
<strong>Updated</strong> <strong>Updated</strong>
<time datetime={dateUpdatedDatetime} title={dateUpdatedFull}>{dateUpdatedRelative}</time> <time datetime={dateUpdatedDatetime} title={dateUpdatedFull}>{dateUpdatedRelative}</time>
@@ -159,11 +159,12 @@
</div> </div>
{#if illu_desktop || illu_mobile} {#if illu_desktop || illu_mobile}
<div class="place__illustration" <div class="place__illustration">
style="{`--url-desktop: ${illu_desktop ? `url(${illu_desktop.full_url});` : undefined}`} <div style="{`--url-desktop: ${illu_desktop ? `url(${illu_desktop.full_url});` : undefined}`}
{`--url-desktop-2x: ${illu_desktop_2x ? `url(${illu_desktop_2x.full_url});` : undefined}`} {`--url-desktop-2x: ${illu_desktop_2x ? `url(${illu_desktop_2x.full_url});` : undefined}`}
{`--url-mobile: ${illu_mobile ? `url(${illu_mobile.full_url});` : undefined}`}" {`--url-mobile: ${illu_mobile ? `url(${illu_mobile.full_url});` : undefined}`}"
/> />
</div>
{/if} {/if}
</section> </section>
@@ -172,7 +173,7 @@
<aside class="photos__side"> <aside class="photos__side">
<Switcher type="switcher--side" /> <Switcher type="switcher--side" />
{#if photos} {#if photos.length}
<p class="updated style-caps"> <p class="updated style-caps">
<strong>Updated</strong> <strong>Updated</strong>
<time datetime={dateUpdatedDatetime} title={dateUpdatedFull}>{dateUpdatedRelative}</time> <time datetime={dateUpdatedDatetime} title={dateUpdatedFull}>{dateUpdatedRelative}</time>
@@ -184,16 +185,11 @@
{#if photos} {#if photos}
<div class="photos__view wrap"> <div class="photos__view wrap">
{#each paginatedPhotos as photo, index} {#each paginatedPhotos as photo, index}
<Photo <Photo {photo} index={photos.length - photos.indexOf(photo)} />
photo={photo}
index={photos.length - photos.indexOf(photo)}
layout={layoutSetting}
/>
{/each} {/each}
</div> </div>
<Pagination <Pagination {photos} {paginatedPhotos} {photosPerPage}
{photos} {paginatedPhotos} {photosPerPage}
on:updatePagination={updatePagination} on:updatePagination={updatePagination}
/> />
@@ -205,4 +201,4 @@
</section> </section>
<Footer /> <Footer />
</Transition> </main>

View File

@@ -36,7 +36,8 @@
locations, locations,
currentLocation, currentLocation,
currentPhotos, currentPhotos,
pageReady pageReady,
pageAnimation
} from 'utils/store' } from 'utils/store'
import { getThumbnail } from 'utils/functions' import { getThumbnail } from 'utils/functions'
@@ -56,6 +57,7 @@
// Variables // Variables
const { page } = stores() const { page } = stores()
pageAnimation.set(animateIn)
let windowWidth let windowWidth
let gotoLink let gotoLink
let currentPhoto = photos.find(photo => photo.slug === $page.params.photo) let currentPhoto = photos.find(photo => photo.slug === $page.params.photo)
@@ -100,7 +102,7 @@
<svelte:window bind:innerWidth={windowWidth} /> <svelte:window bind:innerWidth={windowWidth} />
<Transition {animateIn}> <main class="housesof" class:is-transitioning={!$pageReady}>
<section class="viewer"> <section class="viewer">
<div class="viewer__top"> <div class="viewer__top">
<p class="tip">Tap for fullscreen</p> <p class="tip">Tap for fullscreen</p>
@@ -120,12 +122,11 @@
<a href="/" bind:this={gotoLink} aria-hidden="true" hidden class="hidden" sapper-noscroll>&nbsp;</a> <a href="/" bind:this={gotoLink} aria-hidden="true" hidden class="hidden" sapper-noscroll>&nbsp;</a>
</div> </div>
<Carousel <Carousel {photos}
viewer="true" viewer="true"
photos={photos}
on:photoChange={photoChanged} on:photoChange={photoChanged}
/> />
<Fullscreen /> <Fullscreen />
</section> </section>
</Transition> </main>

View File

@@ -14,16 +14,16 @@
// Globe // Globe
.globe { .globe {
margin-top: -96px; // margin-top: -96px;
margin-bottom: -160px; // margin-bottom: -160px;
@include breakpoint (sm) { // @include breakpoint (sm) {
margin-bottom: calc(-120px - 6vw); // margin-bottom: calc(-120px - 6vw);
} // }
@include breakpoint (xl) { // @include breakpoint (xl) {
margin-top: -176px; // margin-top: -176px;
margin-bottom: -240px; // margin-bottom: -240px;
} // }
} }
// Browse // Browse

View File

@@ -4,7 +4,7 @@
top: 0; top: 0;
left: 0; left: 0;
width: 100%; width: 100%;
transition: opacity 0.4s $ease-quart; transition: opacity 0.3s $ease-quart;
will-change: opacity; will-change: opacity;
&.is-transitioning { &.is-transitioning {

View File

@@ -8,6 +8,21 @@
cursor: grab; cursor: grab;
user-select: none; user-select: none;
////DEBUG////
background: rgba(255,0,0,0.2);
&:after {
content: "";
display: block;
background: blue;
position: absolute;
left: 0; top: 50%;
width: 100%;
height: 2px;
margin-top:-1px;
}
////END DEBUG////
@include breakpoint (sm) { @include breakpoint (sm) {
height: 140vw; height: 140vw;
} }
@@ -23,15 +38,15 @@
height: 35vw; height: 35vw;
min-height: 400px; min-height: 400px;
padding: 0; padding: 0;
// Partial globe // Partial globe
.globe { // .globe {
margin-top: -18vw; // margin-top: -18vw;
} // }
} }
}
// Marker // Marker
.marker { .marker {
position: absolute; position: absolute;
z-index: 2; z-index: 2;
cursor: pointer; cursor: pointer;
@@ -82,7 +97,6 @@
&, span { &, span {
opacity: 1; opacity: 1;
} }
.marker { .marker {
&__city { &__city {
color: #FF6C89; color: #FF6C89;
@@ -92,10 +106,10 @@
} }
} }
} }
} }
.marker.is-left { .marker.is-left {
.marker__label { .marker__label {
left: auto; left: auto;
right: 360%; right: 360%;
@@ -103,14 +117,14 @@
.marker__country { .marker__country {
text-align: right; text-align: right;
} }
}
// Grabbing
&.is-grabbing {
cursor: grabbing;
}
} }
// Grabbing
.markerWrapper.is-grabbing {
cursor: grabbing;
}
// Part globe // Part globe
.globe--part { .globe--part {

View File

@@ -79,16 +79,16 @@
} }
// Globe // Globe
.globe { // .globe {
margin-bottom: calc(-200px - 8vw); // margin-bottom: calc(-200px - 8vw);
@include breakpoint (sm) { // @include breakpoint (sm) {
margin-bottom: calc(-100px - 28vw); // margin-bottom: calc(-100px - 28vw);
} // }
@include breakpoint (xl) { // @include breakpoint (xl) {
margin-bottom: -550px; // margin-bottom: -550px;
} // }
} // }
// Browse // Browse
.browse { .browse {

View File

@@ -92,7 +92,7 @@
} }
// Globe // Globe
.globe__cut { // .globe__cut {
margin-top: 8vw; // margin-top: 8vw;
} // }
} }

View File

@@ -165,17 +165,23 @@
position: absolute; position: absolute;
z-index: 0; z-index: 0;
top: 0; top: 0;
left: 50%; left: 0;
width: 100%; width: 100%;
max-width: 1920px; max-width: 1920px;
height: 100%; height: 100%;
will-change: transform, opacity;
div {
position: relative;
left: 50%;
width: 100%;
height: 100%;
transform: translateX(-50%); transform: translateX(-50%);
transform-origin: 0 0; transform-origin: 0 0;
background-image: var(--url-mobile); background-image: var(--url-mobile);
background-position: 0 0; background-position: 0 0;
background-repeat: no-repeat; background-repeat: no-repeat;
background-size: 100% auto; background-size: 100% auto;
will-change: transform, opacity;
@include breakpoint (sm) { @include breakpoint (sm) {
background-image: var(--url-desktop); background-image: var(--url-desktop);
@@ -185,4 +191,6 @@
background-image: var(--url-desktop-2x); background-image: var(--url-desktop-2x);
} }
} }
}
} }

View File

@@ -10,20 +10,6 @@
<link rel="icon" type="image/png" sizes="64x64" href="/img/favicon.png"> <link rel="icon" type="image/png" sizes="64x64" href="/img/favicon.png">
<link rel="apple-touch-icon" sizes="180x180" href="/img/siteicon.png"> <link rel="apple-touch-icon" sizes="180x180" href="/img/siteicon.png">
<link rel="preconnect" href="https://api.housesof.world" crossorigin>
<link rel="dns-prefetch" href="https://api.housesof.world">
<link rel="preconnect" href="https://www.googletagmanager.com" crossorigin>
<link rel="dns-prefetch" href="https://www.googletagmanager.com">
<link rel="preconnect" href="https://stats.g.doubleclick.net" crossorigin>
<link rel="dns-prefetch" href="https://stats.g.doubleclick.net">
<link rel="preconnect" href="https://www.google-analytics.com" crossorigin>
<link rel="dns-prefetch" href="https://www.google-analytics.com">
<link rel="preload" href="/fonts/G-Light.woff2" as="font" type="font/woff2" crossorigin>
<link rel="preload" href="/fonts/G-Regular.woff2" as="font" type="font/woff2" crossorigin>
<link rel="preload" href="/fonts/G-Semibold.woff2" as="font" type="font/woff2" crossorigin>
<link rel="preload" href="/fonts/M-Extralight.woff2" as="font" type="font/woff2" crossorigin>
<link rel="preload" href="/fonts/M-Light.woff2" as="font" type="font/woff2" crossorigin>
%sapper.base% %sapper.base%
%sapper.head% %sapper.head%
%sapper.styles% %sapper.styles%

View File

@@ -1,10 +1,16 @@
<script> <script>
import { onMount } from 'svelte'
import { fly, fade } from 'svelte/transition' import { fly, fade } from 'svelte/transition'
import { quartInOut, quartOut } from 'svelte/easing' import { quartInOut, quartOut } from 'svelte/easing'
import { stores } from '@sapper/app' import { stores } from '@sapper/app'
import { pageReady, firstLoad, animDelayPanel } from 'utils/store' import {
pageReady,
pageAnimation,
animDuration,
animDelay,
animPanelDelay
} from 'utils/store'
const { page } = stores() const { page } = stores()
$: animateIn = $pageAnimation
// Animations // Animations
import { panelBackgroundOut } from 'animations/Transition' import { panelBackgroundOut } from 'animations/Transition'
@@ -14,44 +20,57 @@
import IconGlobe from 'atoms/IconGlobe' import IconGlobe from 'atoms/IconGlobe'
// Props and Variables // Props and Variables
export let animateIn = scope => {}
let scope let scope
let show = false let show = false
let firstLoad = true
let previousPage = ''
// Check if path is excluded
const isExcluded = path => path.includes(['/viewer/'])
// Listen for route change
page.subscribe(page => {
// Show transition if page is not excluded
if (!isExcluded(previousPage) || !isExcluded(page.path)) {
pageReady.set(false)
process.browser && requestAnimationFrame(() => show = false)
}
// Update page for viewer navigation checking
previousPage = page.path
})
// Listen for when a route is mounted // Listen for when a route is mounted
pageReady.subscribe(loaded => { pageReady.subscribe(loaded => {
loaded && setTimeout(() => { if (loaded) {
// Display page content setTimeout(() => {
// Show transition
show = true show = true
// Run the page animation
process.browser && requestAnimationFrame(() => animateIn())
// Change loader icon as the loader shown already // Change loader icon as the loader shown already
firstLoad.set(false) firstLoad = false
// Scroll to page top // Scroll to page top
window.scrollTo(0,0) window.scrollTo(0,0)
// Run the page animation / after a tiny delay }, firstLoad ? animPanelDelay : 600)
requestAnimationFrame(() => animateIn(scope)) }
}, animDelayPanel)
}) })
</script> </script>
{#if show || !process.browser} {#if !show}
<slot />
{:else}
<div class="transition" id="transition" aria-hidden="true" bind:this={scope}> <div class="transition" id="transition" aria-hidden="true" bind:this={scope}>
<div class="transition__loader" <div class="transition__loader"
in:fly={{ y: 32, duration: 1000, easing: quartOut }} in:fly={{ y: 24, duration: 800, easing: quartOut }}
out:fly={{ y: -window.innerHeight/2, duration: 1400, easing: quartInOut }} out:fly={{ y: -window.innerHeight/2, duration: animDuration, easing: quartInOut }}
> >
{#if $firstLoad} {#if firstLoad}
<TitleSite init={true} /> <TitleSite init={true} />
{:else} {:else}
<IconGlobe width="44" color="#fff" animated="true" /> <IconGlobe width="44" color="#fff" animated="true" />
{/if} {/if}
</div> </div>
<div class="transition__background" <div class="transition__background"
in:fade={{ duration: 600, easing: quartInOut }} out:panelBackgroundOut={{ duration: animDuration }}
out:panelBackgroundOut={{ duration: 1400 }}
/> />
</div> </div>
{/if} {/if}

View File

@@ -1,10 +1,11 @@
import { apiEndpoints } from './store' import { apiEndpoints } from './store'
/* /*
** Get thumbnail from API ** Get thumbnail from API
*/ */
export const getThumbnail = (id, width, height, type = 'crop', quality = 75) => { export const getThumbnail = (id, width, height, type = 'crop', quality = 80) => {
const ratio = 1.5 const ratio = 1.5
width = !width ? Math.round(height * ratio) : width width = !width ? Math.round(height * ratio) : width
height = !height ? Math.round(width / ratio) : height height = !height ? Math.round(width / ratio) : height

View File

@@ -25,14 +25,14 @@ export let currentPhotos = writable()
// State // State
export let pageReady = writable(false, () => {}) export let pageReady = writable(false, () => {})
export let firstLoad = writable(true) export let fullscreen = writable(undefined, () => {})
export let fullscreen = writable()
/* ========================================================================== /* ==========================================================================
Animation related Animation related
========================================================================== */ ========================================================================== */
export const animDelay = 800 export let pageAnimation = writable(() => {}, () => {})
export const animDelayPanel = 1000 export const animDelay = 900
export const animPanelDelay = 900
export const animDuration = 1400 export const animDuration = 1400
export const animDurationLong = 1800 export const animDurationLong = 1800

BIN
static/img/globe/map-3k.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 46 KiB