Remove old Globe

This commit is contained in:
2022-09-25 13:23:55 +02:00
parent bae3b4cdf7
commit 193f6dc2ee
47 changed files with 301 additions and 9037 deletions

View File

@@ -3,140 +3,159 @@
</style> </style>
<script lang="ts"> <script lang="ts">
import { onMount, getContext } from 'svelte' import { getContext, onMount } from 'svelte'
import { getPosition, getRandomItem } from '$utils/functions' import { fade, fly as flySvelte } from 'svelte/transition'
import { quartOut } from 'svelte/easing'
import { Globe, type Marker } from '$modules/globe'
import { getRandomItem, debounce } from '$utils/functions'
import reveal from '$animations/reveal'
// Components
import SplitText from '$components/SplitText.svelte'
const isDev = import.meta.env.DEV
export let type: string = undefined export let type: string = undefined
export let autoRotate: boolean = true export let enableMarkers: boolean = true
export let scrollSmooth: number = 0.5 export let enableMarkersLinks: boolean = true
export let opacity: number = 1 export let speed: number = 0.1
export let pane: boolean = isDev
export let width: number = undefined
let InteractiveGlobe: any
let globeEl: HTMLElement
let observer: IntersectionObserver
let globe: any
let innerWidth: number let innerWidth: number
let innerHeight: number let globeParentEl: HTMLElement, globeEl: HTMLElement
let containerTop = 0 let globe: any
let containerHeight = 0 let observer: IntersectionObserver
let animation: number
$: globeResolution = innerWidth > 1440 && window.devicePixelRatio > 1 ? '4k' : '2k' let hoveredMarker: { name: string, country: string } = null
const { continents, locations }: any = getContext('global') const { continents, locations }: any = getContext('global')
const randomContinent: any = getRandomItem(continents.filter((cont: any) => cont.countries)) const randomContinent: any = getRandomItem(continents)
const markers = locations.map(({ name, slug, country, globe_close: isClose, coordinates: { coordinates }}: any) => ({ const markers = locations.map(({ name, slug, country, coordinates: { coordinates }}): Marker => ({
name, name,
slug, slug,
countryName: country.name, country: { ...country },
countrySlug: country.slug,
lat: coordinates[1], lat: coordinates[1],
lng: coordinates[0], lng: coordinates[0],
className: isClose ? 'is-close' : '',
})) }))
/* onMount(() => {
** Functions const globeResolution = innerWidth > 1440 && window.devicePixelRatio > 1 ? 4 : 2
*/
// Globe update
const update = () => {
requestAnimationFrame(update)
globe.update()
}
// On scroll globe = new Globe({
const handleScroll = () => {
let scrollDiff = (containerTop + innerHeight + (containerHeight - innerHeight) / 2) - document.documentElement.scrollTop
let scrollRatio = (1 - (scrollDiff / innerHeight)) * 2
if (globe) {
globe.updateCameraPos(scrollRatio, scrollDiff - innerHeight)
}
}
// On resize
const handleResize = () => {
if (globeEl && globe) {
containerTop = getPosition(globeEl).top
containerHeight = globeEl.clientHeight
requestAnimationFrame(() => {
globe.resize()
globe.update()
handleScroll()
})
}
}
/*
** Run code when mounted
*/
onMount(async () => {
// Import libraries and code
const { default: InteractiveGlobe } = await import('$modules/globe')
// Init the globe from library
globe = new InteractiveGlobe({
el: globeEl, el: globeEl,
//cameraDistance: size, // Smaller number == larger globe parent: globeParentEl,
autoRotationSpeed: autoRotate ? -0.0025 : 0, mapFile: `/images/globe-map-${globeResolution}k.png`,
rotationStart: randomContinent.rotation, // In degrees mapFileDark: `/images/globe-map-dark-${globeResolution}k.png`,
scrollSmoothing: scrollSmooth, dpr: Math.min(Math.round(window.devicePixelRatio), 2),
opacity: opacity, autoRotate: true,
texture: `/images/globe-map-${globeResolution}.png`, speed,
sunAngle: 2,
rotationStart: randomContinent.rotation,
enableMarkers,
enableMarkersLinks: enableMarkersLinks && type !== 'cropped',
markers, markers,
onLinkClicked: () => {} pane,
}) })
// Run the globe resize()
update()
setTimeout(() => {
handleResize()
handleScroll()
}, 1000)
// Render only if in viewport
// Enable/Disable the globe when shown/hidden observer = new IntersectionObserver(([{ isIntersecting }]) => {
const globeCanvas = document.querySelector('.globe-canvas')
observer = new IntersectionObserver(entries => {
entries.forEach(({ isIntersecting }: IntersectionObserverEntry) => {
if (isIntersecting) { if (isIntersecting) {
globe.enable() update()
globeCanvas.classList.remove('is-hidden')
} else { if (isDev) {
globe.disable() console.log('globe: render/start')
globeCanvas.classList.add('is-hidden')
} }
}) } else {
}, { stop()
threshold: 0,
rootMargin: '0px 0px 0px' if (isDev) {
}) console.log('globe: render/stop')
}
}
}, { threshold: 0 })
observer.observe(globeEl) observer.observe(globeEl)
// Destroy // Destroy
return () => { return () => {
globe && globe.destroy() destroy()
observer && observer.disconnect()
} }
}) })
/**
* Methods
*/
// Update
const update = () => {
animation = requestAnimationFrame(update)
globe.render()
}
// Stop
const stop = () => {
cancelAnimationFrame(animation)
}
// Resize
const resize = debounce(() => {
globe.resize()
}, 100)
// Destroy
const destroy = () => {
stop()
globe.destroy()
}
</script> </script>
<svelte:window <svelte:window bind:innerWidth
on:scroll={handleScroll} on:resize={resize}
on:resize={handleResize}
bind:innerHeight
bind:innerWidth
/> />
<div class="globe" bind:this={globeParentEl}
<section id="globe"> class:is-cropped={type === 'cropped'}
{#if type === 'cropped'} style:--width={width ? `${width}px` : null}
<div class="globe-cropped"> >
<div class="globe" bind:this={globeEl} /> <div class="globe__canvas" bind:this={globeEl}
class:is-faded={hoveredMarker}
>
<ul class="globe__markers">
{#each markers as { name, slug, country, lat, lng }}
<li class="globe__marker" data-location={slug} data-lat={lat} data-lng={lng}>
<a href="/{country.slug}/{slug}" data-sveltekit-noscroll
on:mouseenter={() => hoveredMarker = { name, country: country.name }}
on:mouseleave={() => hoveredMarker = null}
>
<i />
<span>{name}</span>
</a>
</li>
{/each}
</ul>
</div>
{#if hoveredMarker}
<div class="globe__location"
transition:fade={{ duration: 300, easing: quartOut }}
use:reveal={{
children: '.char',
animation: { y: ['110%', 0] },
options: {
stagger: 0.04,
duration: 1,
threshold: 0,
},
}}
>
<SplitText text={hoveredMarker.name} mode="chars" class="name" />
<p class="country" in:flySvelte={{ y: 16, duration: 800, easing: quartOut, delay: 900 }}>
{hoveredMarker.country}
</p>
</div> </div>
{:else}
<div class="globe" bind:this={globeEl} />
{/if} {/if}
</section> </div>

View File

@@ -1,161 +0,0 @@
<style lang="scss">
@import "../../style/modules/globe2";
</style>
<script lang="ts">
import { getContext, onMount } from 'svelte'
import { fade, fly as flySvelte } from 'svelte/transition'
import { quartOut } from 'svelte/easing'
import { Globe, type Marker } from '$modules/globe2'
import { getRandomItem, debounce } from '$utils/functions'
import reveal from '$animations/reveal'
// Components
import SplitText from '$components/SplitText.svelte'
const isDev = import.meta.env.DEV
export let type: string = undefined
export let enableMarkers: boolean = true
export let enableMarkersLinks: boolean = true
export let speed: number = 0.1
export let pane: boolean = isDev
export let width: number = undefined
let innerWidth: number
let globeParentEl: HTMLElement, globeEl: HTMLElement
let globe: any
let observer: IntersectionObserver
let animation: number
let hoveredMarker: { name: string, country: string } = null
const { continents, locations }: any = getContext('global')
const randomContinent: any = getRandomItem(continents)
const markers = locations.map(({ name, slug, country, coordinates: { coordinates }}): Marker => ({
name,
slug,
country: { ...country },
lat: coordinates[1],
lng: coordinates[0],
}))
onMount(() => {
const globeResolution = innerWidth > 1440 && window.devicePixelRatio > 1 ? 4 : 2
globe = new Globe({
el: globeEl,
parent: globeParentEl,
mapFile: `/images/globe-map-${globeResolution}k.png`,
mapFileDark: `/images/globe-map-dark-${globeResolution}k.png`,
dpr: Math.min(Math.round(window.devicePixelRatio), 2),
autoRotate: true,
speed,
sunAngle: 2,
rotationStart: randomContinent.rotation,
enableMarkers,
enableMarkersLinks: type !== 'cropped',
markers,
pane,
})
resize()
// Render only if in viewport
observer = new IntersectionObserver(([{ isIntersecting }]) => {
if (isIntersecting) {
update()
if (isDev) {
console.log('globe: render/start')
}
} else {
stop()
if (isDev) {
console.log('globe: render/stop')
}
}
}, { threshold: 0 })
observer.observe(globeEl)
// Destroy
return () => {
destroy()
observer && observer.disconnect()
}
})
/**
* Methods
*/
// Update
const update = () => {
animation = requestAnimationFrame(update)
globe.render()
}
// Stop
const stop = () => {
cancelAnimationFrame(animation)
}
// Resize
const resize = debounce(() => {
globe.resize()
}, 100)
// Destroy
const destroy = () => {
stop()
globe.destroy()
}
</script>
<svelte:window bind:innerWidth
on:resize={resize}
/>
<div class="globe" bind:this={globeParentEl}
class:is-cropped={type === 'cropped'}
style:--width={width ? `${width}px` : null}
>
<div class="globe__canvas" bind:this={globeEl}
class:is-faded={hoveredMarker}
>
<ul class="globe__markers">
{#each markers as { name, slug, country, lat, lng }}
<li class="globe__marker" data-location={slug} data-lat={lat} data-lng={lng}>
<a href="/{country.slug}/{slug}" data-sveltekit-noscroll
on:mouseenter={() => hoveredMarker = { name, country: country.name }}
on:mouseleave={() => hoveredMarker = null}
>
<i />
<span>{name}</span>
</a>
</li>
{/each}
</ul>
</div>
{#if hoveredMarker}
<div class="globe__location"
transition:fade={{ duration: 300, easing: quartOut }}
use:reveal={{
children: '.char',
animation: { y: ['110%', 0] },
options: {
stagger: 0.04,
duration: 1,
threshold: 0,
},
}}
>
<SplitText text={hoveredMarker.name} mode="chars" class="name" />
<p class="country" in:flySvelte={{ y: 16, duration: 800, easing: quartOut, delay: 900 }}>
{hoveredMarker.country}
</p>
</div>
{/if}
</div>

View File

@@ -1,26 +0,0 @@
class ArrayBuffer {
constructor(gl, data, size, element, name) {
this.name = name;
this.gl = gl;
this._buffer = this.gl.createBuffer();
this.type = this.gl.FLOAT;
this._target = this.gl[ element ? 'ELEMENT_ARRAY_BUFFER' : 'ARRAY_BUFFER' ];
this.update(data, size);
}
update(data, size) {
this.data = data;
this.size = size;
this.length = this.data.length;
this.gl.bindBuffer( this._target, this._buffer);
this.gl.bufferData( this._target, this.data, this.gl.STATIC_DRAW);
}
bind() {
this.gl.bindBuffer( this._target, this._buffer );
}
}
export default ArrayBuffer;

View File

@@ -1,336 +0,0 @@
import Object3d from './Object3d';
import Container from './Container';
import * as mat4 from './glMatrix/mat4';
import * as vec3 from './glMatrix/vec3';
import * as quat from './glMatrix/quat';
const TOUCH = ('ontouchstart' in window) || (navigator.msMaxTouchPoints > 0);
const POINTER = !!window.navigator.pointerEnabled;
const MS_POINTER = !!window.navigator.msPointerEnabled;
const POINTER_DOWN = TOUCH ? 'touchstart' : (POINTER ? 'pointerdown' : (MS_POINTER ? 'MSPointerDown' : 'mousedown' ) );
const POINTER_MOVE = TOUCH ? 'touchmove' : (POINTER ? 'pointermove' : (MS_POINTER ? 'MSPointerMove' : 'mousemove' ) );
const POINTER_UP = TOUCH ? 'touchend' : (POINTER ? 'pointerup' : (MS_POINTER ? 'MSPointerUp' : 'mouseup' ) );
var objects = []
function needsUpdateLoop() {
requestAnimationFrame(needsUpdateLoop);
for (let i=0; i<objects.length; i++) {
objects[i]._canUpdate = true;
}
}
needsUpdateLoop();
class Camera extends Object3d {
constructor(options) {
super();
options = Object.assign({},{
fov: 45,
aspect: window.innerWidth / window.innerHeight,
near: 10,
far: 1000,
type: 'perspective',
left: 0,
right: 0,
top: 0,
bottom: 0,
orbitControl: false,
lookAt: null,
pointerParent: document,
firstPerson: false,
moveSpeed: 20,
distance: 20,
wheel: true,
position: [0,0,0]
}, options);
this.fov = options.fov;
this.aspect = options.aspect;
this.near = options.near;
this.far = options.far;
this.type = options.type;
this.left = options.left;
this.right = options.right;
this.top = options.top;
this.bottom = options.bottom;
this.orbitControl = options.orbitControl;
this.firstPerson = options.firstPerson;
this.wheel = options.wheel;
this.projectionMatrix = mat4.create();
this.updateProjectionMatrix();
if ( this.orbitControl || this.firstPerson ) {
if (!this.lookAt) {
this.lookAt = vec3.create();
vec3.set(this.lookAt, 0,0,0 );
}
this._pointerParent = options.pointerParent
this._initPointerEvents();
this._cameraDistance = options.position[2];
this._canUpdate = true;
objects.push(this);
}
if (this.firstPerson) {
document.addEventListener("contextmenu", this.onContextMenu.bind(this), false);
document.addEventListener("keydown", this.onKeyDown.bind(this), false);
document.addEventListener("keyup", this.onKeyUp.bind(this), false);
}
this.pitchObject = new Container();
this.yawObject = new Container();
this.yawObject.add( this.pitchObject );
this.moveSpeed = options.moveSpeed;
this.time = Date.now();
this._velocity = vec3.create();
this._moveForward = false;
this._moveBackward = false;
this._moveLeft = false;
this._moveRight = false;
this._moveUp = false;
this._camera = vec3.create()
this._oldPosition = vec3.create();
}
updateProjectionMatrix() {
if (this.type == 'perspective') {
mat4.perspective(this.projectionMatrix, this.fov * Math.PI/180.0, this.aspect, this.near, this.far);
}
else if(this.type == 'orthographic' || this.type == 'ortho'){
mat4.ortho(this.projectionMatrix, this.left, this.right, this.bottom, this.top, this.near, this.far);
}
}
_initPointerEvents() {
this.winWidth = window.innerWidth;
this.winHeight = window.innerHeight;
this._isPointerDown = false;
this.isRightClick = false;
this.pointerXMove = 0;
this.pointerYMove = 0;
this.pointerX = 0;
this.pointerY = 0;
this.pointerZ = 0;
this.lastPointerX = 0;
this.lastPointerY = 0;
this.lastPointerZ = 0;
this.theta = 0;//Math.PI/2;
this.phi = 0;
this.thetaDown = 0;
this.phiDown = 0;
this.currTheta = 0;
this.currPhi = 0;
this._minPolarAngle = Math.PI * -.5; // radians
this._maxPolarAngle = Math.PI * .5; // radians
this._onPointerDown = this._onPointerDown.bind(this);
this._onPointerMove = this._onPointerMove.bind(this);
this._onPointerUp = this._onPointerUp.bind(this);
this._onMouseWheel = this._onMouseWheel.bind(this);
this.onContextMenu = this.onContextMenu.bind(this);
this._pointerParent.addEventListener(POINTER_DOWN, this._onPointerDown, false);
document.addEventListener(POINTER_MOVE, this._onPointerMove, false);
document.addEventListener(POINTER_UP, this._onPointerUp, false);
this._pointerParent.addEventListener( "contextmenu", this.onContextMenu, false);
if (this.wheel) {
this._pointerParent.addEventListener( 'DOMMouseScroll', this._onMouseWheel, false );
this._pointerParent.addEventListener( 'mousewheel', this._onMouseWheel, false );
}
}
delete() {
this._pointerParent.removeEventListener(POINTER_DOWN, this._onPointerDown, false);
document.removeEventListener(POINTER_MOVE, this._onPointerMove, false);
document.removeEventListener(POINTER_UP, this._onPointerUp, false);
this._pointerParent.removeEventListener( "contextmenu", this.onContextMenu, false);
if (this.wheel) {
this._pointerParent.removeEventListener( 'DOMMouseScroll', this._onMouseWheel, false );
this._pointerParent.removeEventListener( 'mousewheel', this._onMouseWheel, false );
}
}
onContextMenu(e) {
event.preventDefault();
}
onKeyDown(event) {
switch ( event.keyCode ) {
// case 38: // up
case 87: // w
this._moveForward = true;
break;
// case 37: // left
case 65: // a
this._moveLeft = true; break;
// case 40: // down
case 83: // s
this._moveBackward = true;
break;
// case 39: // right
case 68: // d
this._moveRight = true;
break;
case 32: // space
this._velocity[1] += 5;
break;
}
}
onKeyUp(event) {
switch( event.keyCode ) {
case 38: // up
case 87: // w
this._moveForward = false;
break;
case 37: // left
case 65: // a
this._moveLeft = false;
break;
case 40: // down
case 83: // s
this._moveBackward = false;
break;
case 39: // right
case 68: // d
this._moveRight = false;
break;
}
}
_onMouseWheel(e) {
// e.preventDefault();
e.stopPropagation();
var wheelDeltaX, wheelDeltaY;
if ( e.wheelDelta ){
wheelDeltaX = wheelDeltaY = e.wheelDelta; //6 or 12
} else if ( e.detail ){
wheelDeltaX = wheelDeltaY = -e.detail * 40; // *3
} else if ( e.wheelDeltaX ) {
wheelDeltaY = e.wheelDeltaY/12;
wheelDeltaX = -1 * e.wheelDeltaX/12;
} else if ( e.axis !== undefined && e.axis === e.HORIZONTAL_AXIS ) {
wheelDeltaY = 0;
wheelDeltaX = -1 * wheelDeltaY;
} else {
wheelDeltaY = 0;
wheelDeltaX = 0;
}
// this._cameraDistance += wheelDeltaY * -2 * 0.01;
// this._cameraDistance = Math.max(3, Math.min(5, this._cameraDistance));
}
_onPointerDown(event) {
if (event.which == 3) {
this.isRightClick = true;
// event.preventDefault();
// event.stopPropagation();
}
this._isPointerDown = true;
this._pointerParent.classList.add('is-grabbing')
this.touchEvent = TOUCH ? (event.touches[0] || event.changedTouches[0]) : event;
this.touchEventPageX = this.touchEvent.pageX;
this.touchEventPageY = this.touchEvent.pageY;
this.touchEventPageX -= window.pageXOffset || document.documentElement.scrollLeft;
this.touchEventPageY -= window.pageYOffset || document.documentElement.scrollTop;
this.pointerXDown = this.touchEventPageX;
this.pointerYDown = this.touchEventPageY;
if (this.isRightClick) {
this.startPointerX = this.pointerXMove;
this.startPointerY = this.pointerYMove;
}
this.thetaDown = this.theta;
this.phiDown = this.phi;
}
_onPointerMove(event) {
if( !this._isPointerDown){
return;
}
// event.preventDefault();
this.touchEvent = TOUCH ? (event.touches[0] || event.changedTouches[0]) : event;
this.touchEventPageX = this.touchEvent.pageX;
this.touchEventPageY = this.touchEvent.pageY;
this.touchEventPageX -= window.pageXOffset || document.documentElement.scrollLeft;
this.touchEventPageY -= window.pageYOffset || document.documentElement.scrollTop;
if (this.isRightClick) {
this.pointerXMove = this.startPointerX + (this.touchEventPageX - this.pointerXDown);
this.pointerYMove = this.startPointerY + (this.touchEventPageY - this.pointerYDown);
}
else {
this.pointerXOrbiter = (this.pointerXDown - this.touchEventPageX);
this.pointerYOrbiter = (this.pointerYDown - this.touchEventPageY);
this.theta = this.thetaDown + ( this.pointerXOrbiter / this.winWidth * 2 * Math.PI);
this.phi = this.phiDown + ( this.pointerYOrbiter / this.winHeight * 2 * Math.PI * -1);
this.phi = Math.max( this._minPolarAngle, Math.min( this._maxPolarAngle, this.phi ) );
if( TOUCH ) {
this.phi = 0;
}
}
}
_onPointerUp() {
this._isPointerDown = false;
this.isRightClick = false;
this._pointerParent.classList.remove('is-grabbing')
}
update(force) {
if (this.orbitControl) {
if (this._canUpdate || force) {
this.currTheta += (this.theta - this.currTheta) * 0.1;
this.currPhi += (this.phi - this.currPhi) * 0.1;
this.position[0] = Math.sin(this.currTheta) * Math.cos(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;
super.render();
}
}
else {
super.render();
}
this._canUpdate = false;
}
}
export default Camera;

View File

@@ -1,53 +0,0 @@
import Object3d from './Object3d';
class Container extends Object3d {
constructor() {
super();
this.visible = true;
this.parent = null;
this.children = [];
}
add(child) {
for (let i=0,l=this.children.length;i<l; i++) {
if (this.children[i] == child) {
break;
}
}
this.children.push(child);
child.parent = this;
}
remove(child) {
for (let i=0,l=this.children.length;i<l; i++) {
if (this.children[i] == child) {
child.parent = null;
this.children.splice(i, 1);
break;
}
}
}
destroy() {
for (let i=0,l=this.children.length;i<l; i++) {
this.children[i].destroy();
}
if (this.parent !== null) {
this.parent.removeChild( this );
}
}
render(camera, options) {
super.render();
for (let i=0,l=this.children.length;i<l; i++) {
if (this.children[i].visible) {
this.children[i].render(camera, options);
}
}
}
}
export default Container;

View File

@@ -1,30 +0,0 @@
import ArrayBuffer from './ArrayBuffer';
class GeometryBuffer {
constructor(gl, size) {
if (!gl) {
return;
}
this.gl = gl;
this.attributes = {}
this.length = size || 0;
// this.vertices = [];
// this.addAttribute( 'index', new Uint16Array( this.indices ), 1 );
// this.addAttribute( 'position', new Float32Array( this.vertices ), 3 );
// this.addAttribute( 'normal', new Float32Array( this.normals ), 3 );
// this.addAttribute( 'uv', new Float32Array( this.uvs ), 2 );
}
addAttribute(attribName, data, size, geometry) {
this.attributes[attribName] = new ArrayBuffer(this.gl, data, size, attribName === 'index', geometry);//true=use element array buffer
}
}
export default GeometryBuffer;

View File

@@ -1,54 +0,0 @@
import Program from './Program';
import vertexShader from './shaders/default-vs.glsl?raw';
import fragmentShader from './shaders/mesh-fs.glsl?raw';
class Material extends Program {
constructor( gl, options ){
options = Object.assign({}, {
vertexShader: vertexShader,
fragmentShader: fragmentShader,
map: null,
}, options);
options.uniforms = Object.assign({}, {
color: [1,1,1],
alpha: 1
}, options.uniforms);
options.defines = Object.assign({}, {
USE_MAP: false
}, options.defines);
super(gl, options);
if (!gl) {
return;
}
Object.defineProperty(this, 'map', {
set: (value) => {
if (value) {
this.defines.USE_MAP = true;
this.compile();
if (this.uniforms.map) {
this.uniforms.map.value = value;
}
}
else {
this.defines.USE_MAP = false;
this.compile();
}
}
});
this.map = options.map;
}
}
export default Material;

View File

@@ -1,90 +0,0 @@
import Container from './Container';
import * as mat4 from './glMatrix/mat4';
class Mesh extends Container {
constructor(options) {
super();
this.material = null;
this.geometry = null;
this.options = options || {};
this._viewMatrix = mat4.create()
this._invViewMatrix = mat4.create()
this._modelViewMatrix = mat4.create()
this._normalMatrix = mat4.create()
}
render(camera, options={}) {
super.render( camera, options );
let material = options.overrideMaterial || this.material;
if (camera && material &&
this.geometry && //TODO: check for geometry.length
this.visible) {
if (this.options.beforeRender) {
this.options.beforeRender()
}
// setTimeout(()=>{
mat4.invert(this._viewMatrix, camera.worldMatrix);
mat4.multiply(this._modelViewMatrix, this._viewMatrix, this.worldMatrix);
if (material.uniforms['uInverseViewMatrix'] !== void 0) {
mat4.copy(this._invViewMatrix, camera.worldMatrix);
mat4.invert(this._invViewMatrix, this._invViewMatrix);
material.uniforms['uInverseViewMatrix'].value = camera.worldMatrix;
}
if (material.uniforms['uCameraPosition'] !== void 0) {
material.uniforms['uCameraPosition'].value = camera.position;
}
if (material.uniforms['uVMatrix'] !== void 0) {
material.uniforms['uVMatrix'].value = this._viewMatrix;
}
if (material.uniforms['uNormalMatrix'] !== void 0) {
mat4.multiply( this._normalMatrix, this._rotationMat4, this.parent._rotationMat4);
material.uniforms['uNormalMatrix'].value = this._normalMatrix
}
if (material.uniforms['uMMatrix'] !== void 0) {
material.uniforms['uMMatrix'].value = this.worldMatrix;
// console.log('MANUALLY ASSIGN ', this.matrix, this.name)
// console.log('setMM', this.name, this.matrix[0], this.matrix[1], this.matrix[2], this.matrix[3])
}
if (material.uniforms['uMVMatrix'] !== void 0) {
material.uniforms['uMVMatrix'].value = this._modelViewMatrix;
}
if (material.uniforms['uPMatrix'] !== void 0) {
material.uniforms['uPMatrix'].value = camera.projectionMatrix;
}
for (let u in options.uniforms) {
if (material.uniforms[ u ] !== void 0) {
material.uniforms[ u ].value = options.uniforms[u];
}
}
let needsCompile = false;
for (let k in options.defines) {
if (material.defines[ k ] !== options.defines[ k ]) {
material.defines[ k ] = options.defines[ k ];
needsCompile = true;
}
}
if (needsCompile) {
material.compile();
}
material.draw( this.geometry );
// })
}
}
}
export default Mesh;

View File

@@ -1,142 +0,0 @@
import * as mat4 from './glMatrix/mat4';
import * as mat3 from './glMatrix/mat3';
import * as quat from './glMatrix/quat';
import * as vec3 from './glMatrix/vec3';
class Object3d {
constructor() {
this.position = vec3.create();
this.rotation = vec3.create();
this.scale = vec3.create();
this.lookAt = null;
//use to diff and only update matrix if needed
this.lastPosition = vec3.create();
this.lastRotation = vec3.create();
this.lastScale = vec3.create();
this.lastLookAt = vec3.create();
vec3.set(this.scale, 1, 1, 1);
this.up = vec3.create();
vec3.set(this.up, 0, 1, 0);
this.matrix = mat4.create();//modelMatrix
this.worldMatrix = mat4.create();//modelMatrix * parentMatri(x|ces)
this.quaternion = null;//quat.create();
this._quaternion = quat.create();
this.inverseWorldMatrix = mat4.create();
this._invLookatMat4 = mat4.create();
this._m3Rotation = mat3.create();
this._rotationMat4 = mat4.create();
this._lookAtMat4 = mat4.create();
this._lastUpdate = Date.now()
}
render() {
let needsUpdate = false;
// let needsUpdateOrigin = null;
if (this.position[0] !== this.lastPosition[0] ||
this.position[1] !== this.lastPosition[1] ||
this.position[2] !== this.lastPosition[2] ) {
this.lastPosition[0] = this.position[0];
this.lastPosition[1] = this.position[1];
this.lastPosition[2] = this.position[2];
// needsUpdateOrigin = 'position'
needsUpdate = true;
}
else if (
this.rotation[0] !== this.lastRotation[0] ||
this.rotation[1] !== this.lastRotation[1] ||
this.rotation[2] !== this.lastRotation[2] ) {
this.lastScale[0] = this.rotation[0];
this.lastScale[1] = this.rotation[1];
this.lastScale[2] = this.rotation[2];
// needsUpdateOrigin = 'rotation'
needsUpdate = true;
}
else if (
this.scale[0] !== this.lastScale[0] ||
this.scale[1] !== this.lastScale[1] ||
this.scale[2] !== this.lastScale[2] ) {
this.lastScale[0] = this.scale[0];
this.lastScale[1] = this.scale[1];
this.lastScale[2] = this.scale[2];
// needsUpdateOrigin = 'scale'
needsUpdate = true;
}
else if (
this.lookAt !== null &&
( this.lookAt[0] !== this.lastLookAt[0] ||
this.lookAt[1] !== this.lastLookAt[1] ||
this.lookAt[2] !== this.lastLookAt[2] ) ) {
this.lastLookAt[0] = this.lookAt[0];
this.lastLookAt[1] = this.lookAt[1];
this.lastLookAt[2] = this.lookAt[2];
// needsUpdateOrigin = 'lookAt'
needsUpdate = true;
}
this.updateMatrix();
this.updateWorldMatrix();
}
updateMatrix() {
mat4.identity(this.matrix);
mat4.identity(this._invLookatMat4)
mat3.identity(this._m3Rotation)
mat4.identity(this._rotationMat4)
mat4.identity(this._lookAtMat4)
if (this.quaternion) {
mat4.fromRotationTranslation(this.matrix, this.quaternion, this.position );
}
else {
mat4.translate(this.matrix, this.matrix, this.position);
mat4.rotateX(this._rotationMat4, this._rotationMat4, this.rotation[0]);
mat4.rotateY(this._rotationMat4, this._rotationMat4, this.rotation[1]);
mat4.rotateZ(this._rotationMat4, this._rotationMat4, this.rotation[2]);
}
if (this.lookAt !== null) {
mat4.lookAt(
this.matrix,
this.position,
this.lookAt,
this.up
);
mat4.invert(this.matrix, this.matrix);
mat4.scale(this.matrix, this.matrix, this.scale);
}
else {
mat4.scale(this.matrix, this.matrix, this.scale);
mat4.multiply(this.matrix, this.matrix, this._rotationMat4);
}
}
updateWorldMatrix() {
if (this.parent) {
mat4.multiply(this.worldMatrix, this.parent.worldMatrix, this.matrix );
}
else{
this.worldMatrix = this.matrix;
}
mat4.invert(this.inverseWorldMatrix, this.worldMatrix);
}
}
export default Object3d;

View File

@@ -1,94 +0,0 @@
import GeometryBuffer from './GeometryBuffer';
class PlaneGeometryBuffer extends GeometryBuffer {
constructor(gl, options) {
super(gl, 4.);
options = Object.assign({}, {
width: 1000,
height: 1000,
widthSegments: 1,
heightSegments: 1
}, options);
if (!gl) {
return;
}
this.width = options.width;
this.height = options.height;
this.widthSegments = options.widthSegments;
this.heightSegments = options.heightSegments;
this._build();
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.addAttribute( 'color', new Float32Array( this.colors ), 3 );
}
update() {
this._build();
this.attributes['index'].update( new Uint16Array(this.indices), 1 );
this.attributes['position'].update( new Float32Array(this.vertices), 3 );
this.attributes['normal'].update( new Float32Array(this.normals), 3 );
this.attributes['uv'].update( new Float32Array(this.uvs), 2 );
this.attributes['color'].update( new Float32Array(this.colors), 3 );
}
_build() {
// buffers
this.indices = [];
this.vertices = [];
this.normals = [];
this.uvs = [];
this.colors = [];
var width_half = this.width * 0.5;
var height_half = this.height * 0.5;
var gridX = this.widthSegments >> 0;
var gridY = this.heightSegments >> 0;
var gridX1 = gridX + 1;
var gridY1 = gridY + 1;
var segment_width = this.width / gridX;
var segment_height = this.height / gridY;
var ix, iy;
// generate vertices, normals and uvs
for ( iy = 0; iy < gridY1; iy ++ ) {
var y = iy * segment_height - height_half;
for ( ix = 0; ix < gridX1; ix ++ ) {
var x = ix * segment_width - width_half;
this.vertices.push( x, - y, 0 );
this.normals.push( 0, 0, 1 );
this.uvs.push( ix / gridX, 1 - ( iy / gridY ) );
this.colors.push( 1, 1, 1 );
}
}
// indices
for ( iy = 0; iy < gridY; iy ++ ) {
for ( ix = 0; ix < gridX; ix ++ ) {
var a = ix + gridX1 * iy;
var b = ix + gridX1 * ( iy + 1 );
var c = ( ix + 1 ) + gridX1 * ( iy + 1 );
var d = ( ix + 1 ) + gridX1 * iy;
// faces
this.indices.push( a, b, d );
this.indices.push( b, c, d );
}
}
this.length = this.vertices.length/3;
}
}
export default PlaneGeometryBuffer;

View File

@@ -1,448 +0,0 @@
import UNIFORM_TYPE from './uniformTypes';
import defaultVertexShader from './shaders/default-vs.glsl?raw';
import defaultFragmentShader from './shaders/default-fs.glsl?raw';
import uuid from './utils/uuid';
const TEXTURE_2D = 35678
const TEXTURE_CUBE_MAP = 35680;
function addLineNumbers( string ) {
var lines = string.split( '\n' );
for ( var i = 0; i < lines.length; i ++ ) {
lines[ i ] = ( i + 1 ) + ': ' + lines[ i ];
}
return lines.join( '\n' );
}
function compileShader( gl, shader, code ){
gl.shaderSource( shader, code );
gl.compileShader( shader );
if (!gl.getShaderParameter(shader, gl.COMPILE_STATUS)) {
console.error('Shader cannot compile: \n' + gl.getShaderInfoLog(shader) || "" );
console.warn(addLineNumbers(code));
return false;
}
return true;
}
var _lastUsedDepthTest = null
var _lastUsedGeometry = null
class Program {
constructor(gl, options={}) {
this._uuid = uuid();
if (!gl) {
return;
}
options = Object.assign({}, {
vertexShader: defaultVertexShader,
fragmentShader: defaultFragmentShader,
defines: {},
extentions: {},
uniforms: {},
type: gl.TRIANGLES
}, options);
this.options = options;
this._vertexShaderSource = options.vertexShader;
this._fragmentShaderSource = options.fragmentShader;
this.gl = gl;
this._program = gl.createProgram();
this.vertexShader = gl.createShader( gl.VERTEX_SHADER );
this.fragmentShader = gl.createShader( gl.FRAGMENT_SHADER );
gl.attachShader(this._program, this.vertexShader);
gl.attachShader(this._program, this.fragmentShader);
this.type = options.type;
this.attributes = {};
this.defines = options.defines;
this.extentions = options.extentions;
this._textureUnit = 0;
this.depthTest = options.depthTest !== void 0 ? options.depthTest : true;
this.blend = options.blend !== void 0 ? options.blend : false;
this.blendEquation = options.blendEquation !== void 0 ? options.blendEquation : this.gl.FUNC_ADD;
this.blendSrc = options.blendSrc !== void 0 ? options.blendSrc : this.gl.SRC_ALPHA;
this.blendDst = options.blendDst !== void 0 ? options.blendDst : this.gl.ONE_MINUS_SRC_ALPHA;
this.blendSrcRGB = options.blendSrcRGB !== void 0 ? options.blendSrcRGB : this.gl.SRC_ALPHA;
this.blendDstRGB = options.blendDstRGB !== void 0 ? options.blendDstRGB : this.gl.ONE_MINUS_SRC_ALPHA;
this.blendSrcAlpha = options.blendSrcAlpha !== void 0 ? options.blendSrcAlpha : this.gl.ONE;
this.blendDstAlpha = options.blendDstAlpha !== void 0 ? options.blendDstAlpha : this.gl.ONE_MINUS_SRC_ALPHA;
this.wireframe = options.wireframe !== void 0 ? options.wireframe : false;
this.uniforms = {};
this._userDefinedUniforms = options.uniforms;
this.compile();
}
compile() {
if (!this.gl) {
return;
}
if (this.isCompiling) {
return;
}
this.isCompiling = true;
var defines = '';
for (var d in this.defines) {
if (this.defines[d]) {
defines += '#define '+d+' '+this.defines[d]+'\n';
}
}
if( !( compileShader( this.gl, this.vertexShader, defines + this._vertexShaderSource ) &&
compileShader( this.gl, this.fragmentShader, defines + this._fragmentShaderSource ) ) ) {
console.warn('compile error')
return false;
}
this.gl.linkProgram(this._program);
if (!this.gl.getProgramParameter(this._program, this.gl.LINK_STATUS)) {
console.error("Cannot link program: \n" + this.gl.getProgramInfoLog(this._program) || "");
console.warn("VERTEX_SHADER:\n"+addLineNumbers(this._vertexShaderSource)
+"\n\nFRAGMENT_SHADER:\n"+addLineNumbers(this._fragmentShaderSource));
}
this.gl.useProgram(this._program);
this._retrieveUniformsFromShader();
this.isCompiling = false;
}
_retrieveUniformsFromShader() {
//debug
let isMMatrix = false;
this._savedUniforms = {};
for (let k in this.uniforms) {
this._savedUniforms[k] = {
value: this.uniforms[k].value
}
}
this.uniforms = {};
this._textureUnit = 0;
var numUniforms = this.gl.getProgramParameter( this._program, this.gl.ACTIVE_UNIFORMS );
for (let i = 0; i < numUniforms; ++i) {
var uniform = this.gl.getActiveUniform( this._program, i );
if( uniform === null ){
this.gl.getError();
continue;
}
let name = uniform.name;
let isArray = false;//is uniform array ?(ex: 3fv, 4fv...)
// tltr; we want 'myUniform[0]' to become 'myUniform'
// if array uniform, replace the retrieved name as it includes the first index acces
if (/\[.*\]/.test(name) ) {
isArray = true;
name = name.replace(/\[.*\]/,'');
}
if (this.uniforms[ name ] !== void 0) {
this.uniforms[ name ].location = this.gl.getUniformLocation( this._program, name );
this.uniforms[ name ].type = uniform.type;
}
else {
this.uniforms[ name ] = {
isArray: isArray,
location: this.gl.getUniformLocation( this._program, name ),
type: uniform.type,
value: null,
size: uniform.size
}
//set texture unit
if (uniform.type === TEXTURE_2D || uniform.type === TEXTURE_CUBE_MAP) {
this.uniforms[ name ].unit = this._textureUnit;
this._textureUnit++;
}
}
}
let isEnd = false;
//merge user defined uniforms
for (let u in this._savedUniforms) {
if (this.uniforms[u] !== void 0){
if (this._savedUniforms[u].value !== void 0
&& this._savedUniforms[u].value !== null) {
this.uniforms[u].value = this._savedUniforms[u].value;
}
}
else {
}
}
for (let u in this._userDefinedUniforms) {
if (this.uniforms[u] !== void 0
&& this._userDefinedUniforms[u] !== void 0
&& this._userDefinedUniforms[u] !== null) {
this.uniforms[u].value = this._userDefinedUniforms[u];
}
}
var numAttributes = this.gl.getProgramParameter( this._program, this.gl.ACTIVE_ATTRIBUTES );
for (let i = 0; i < numAttributes; ++i) {
var attribute = this.gl.getActiveAttrib( this._program, i );
if( attribute === null ){
this.gl.getError();
continue;
}
this.attributes[ attribute.name ] = {
location: this.gl.getAttribLocation( this._program, attribute.name ),
type: attribute.type
}
//the attribute is only enabled when the buffer is binded
//(so it's enabled by the Program that will use the buffer)
//this way we make sure that any enabled attribute has some data not to trigger an error
//see http://www.mjbshaw.com/2013/03/webgl-fixing-invalidoperation.html
// this.gl.enableVertexAttribArray( this.attributes[attribute.name].location );
}
}
dispose() {
}
use () {
if (!this.gl) {
return;
}
this.gl.useProgram(this._program);
}
attribPointer(attributes, geometry) {
if (!this.gl) {
return;
}
for (var attr in this.attributes) {
if (attributes[attr] !== void 0) {
attributes[attr].bind();
this.gl.vertexAttribPointer( this.attributes[attr].location, attributes[attr].size, attributes[attr].type, false, 0, 0);
this.gl.enableVertexAttribArray( this.attributes[attr].location );
}
}
}
draw(geometry) {
if (!this.gl) {
return;
}
this.gl.useProgram(this._program);
//todo add a flah on attribute to check if they changed and thus needs to be binded again
//todo check the currently used program to know if it need some buffer bindings
// if (geometry !== _lastUsedGeometry) {
//TODO: check if geometry has changed
this.attribPointer(geometry.attributes, geometry);
// _lastUsedGeometry = geometry;
// }
// if (this.depthTest !== _lastUsedDepthTest) {
this.gl[ this.depthTest ? 'enable' : 'disable' ](this.gl.DEPTH_TEST);
// _lastUsedDepthTest = this.depthTest;
// }
if (this.blend) {
// this.gl.disable(this.gl.DEPTH_TEST);
// this.gl[ this.depthTest ? 'enable' : 'disable' ](this.gl.DEPTH_TEST);
if (this.depthTest) {
this.gl.depthFunc( this.gl.LESS );
}
this.gl.blendEquation(this.blendEquation);
this.gl.blendFuncSeparate(this.blendSrcRGB, this.blendDstRGB, this.blendSrcAlpha, this.blendDstAlpha);
// this.gl.blendFunc(this.blendSrc,this.blendDst);
this.gl.enable(this.gl.BLEND);
}
else {
this.gl.disable(this.gl.BLEND);
// this.gl[ this.depthTest ? 'enable' : 'disable' ](this.gl.DEPTH_TEST);
if (this.depthTest) {
this.gl.depthFunc( this.gl.LESS );
}
}
var keys = Object.keys(this.uniforms);
for (var i=0,l=keys.length; i<l; i++) {
let uniformName = keys[i]
switch (this.uniforms[ uniformName ].type) {
case this.gl.FLOAT_MAT2:
case this.gl.FLOAT_MAT3:
case this.gl.FLOAT_MAT4:
if (this.uniforms[ uniformName ].value !== null &&
this.uniforms[ uniformName ].value !== void 0) {
this.gl['uniform' + UNIFORM_TYPE[this.uniforms[ uniformName ].type]+'v'](this.uniforms[ uniformName ].location, false, this.uniforms[ uniformName ].value);
}
break;
default:
//texture2D
if (this.uniforms[ uniformName ].type === TEXTURE_2D ||
this.uniforms[ uniformName ].type === TEXTURE_CUBE_MAP ){
if (this.uniforms[ uniformName ].value) {
this.uniforms[ uniformName ].value.bind( this.uniforms[ uniformName ].unit );
this.gl['uniform' + UNIFORM_TYPE[this.uniforms[ uniformName ].type] ](this.uniforms[ uniformName ].location, this.uniforms[ uniformName ].unit);
}
else {
// console.log('no value for texture...', keys[i], this._userDefinedUniforms[keys[i]], this.uniforms[ keys[i] ].value, this.defines.USE_ALBEDO_MAP)
}
// if (keys[i] == 'tAlbedo' && this.defines.USE_ALBEDO_MAP) {
// console.log('BIND ALBEDO UNIRFORM', this.uniforms.tAlbedo.value, this.defines)
// }
// drawnUniformsTextures.push(keys[i]);
}
else {
let type = UNIFORM_TYPE[this.uniforms[ keys[i] ].type];
//add 'v' to the uniformType if the unifor is an array: ex "3f" => "3fv"
if (this.uniforms[ uniformName ].isArray) {
type += 'v';
}
if (this.uniforms[ uniformName ].value !== null) {
if (type == '2f') {
this.gl['uniform' + type ](this.uniforms[ uniformName ].location, this.uniforms[ uniformName ].value[0], this.uniforms[ uniformName ].value[1]);
// drawnUniforms2f.push(uniformName);
}
else if (type == '3f') {
this.gl['uniform' + type ](this.uniforms[ uniformName ].location, this.uniforms[ uniformName ].value[0], this.uniforms[ uniformName ].value[1], this.uniforms[ uniformName ].value[2]);
// drawnUniforms3f.push(uniformName);
}
else if (type == '4f') {
this.gl['uniform' + type ](this.uniforms[ uniformName ].location, this.uniforms[ uniformName ].value[0], this.uniforms[ uniformName ].value[1], this.uniforms[ uniformName ].value[2], this.uniforms[ uniformName ].value[3]);
// drawnUniforms4f.push(uniformName);
}
else {
// drawnUniforms1f.push(uniformName);
this.gl['uniform' + type ](this.uniforms[ uniformName ].location, this.uniforms[ uniformName ].value);
}
}
}
//break;
}
}
if ( this.type !== this.gl.POINTS &&
geometry.attributes['index'] ) {
geometry.attributes['index'].bind()
this.gl.drawElements(this.wireframe ? this.gl.LINE_STRIP : this.type, geometry.attributes['index'].length, this.gl.UNSIGNED_SHORT, 0);
}
else {
this.gl.drawArrays(this.wireframe ? this.gl.LINE_STRIP : this.type, 0, geometry.length);
}
}
}
// var drawnUniformsTextures = []
// var drawnUniforms1f = []
// var drawnUniforms2f = []
// var drawnUniforms3f = []
// var drawnUniforms4f = []
// function flushUniforms() {
// console.log('1f: ' + drawnUniforms1f.length + '\n' +
// '2f: ' + drawnUniforms2f.length + '\n' +
// '3f: ' + drawnUniforms3f.length + '\n' +
// '4f: ' + drawnUniforms4f.length + '\n' +
// 'tx: ' + drawnUniformsTextures.length + '\n' );
// drawnUniformsTextures = []
// drawnUniforms1f = []
// drawnUniforms2f = []
// drawnUniforms3f = []
// drawnUniforms4f = []
// requestAnimationFrame(flushUniforms)
// }
// flushUniforms();
export default Program;

View File

@@ -1,103 +0,0 @@
class Renderer {
constructor(options) {
this.canvas = (options && options.canvas) || document.createElement('canvas');
this.canvas.style.transformOrigin = '0 0';
this.contextAttributes = Object.assign({},{
alpha: false,
depth: true,
stencil: true,
antialias: false,
premultipliedAlpha: true,
preserveDrawingBuffer: false,
failIfMajorPerformanceCaveat: false,
}, (options || {}) );
this._pixelRatio = 1;
this.gl = this.canvas.getContext("experimental-webgl", this.contextAttributes);
this.handleContextLost = this.handleContextLost.bind(this);
this.handleContextRestored = this.handleContextRestored.bind(this);
this.canvas.addEventListener('webglcontextlost', this.handleContextLost, false);
this.canvas.addEventListener('webglcontextrestored', this.handleContextRestored, false);
}
handleContextLost(event){
event.preventDefault();
}
handleContextRestored(){
}
handleContextRestored() {
}
render(container, camera, frameBuffer, preventCameraUpdate) {
if (!this.gl) {
return;
}
if (!preventCameraUpdate) {
camera.update();
}
if (frameBuffer){
frameBuffer.bindFrame();
container.render( camera );
frameBuffer.unbind();
}
else{
this.gl.viewport(0, 0, this._width* this._pixelRatio , this._height* this._pixelRatio );
container.render( camera );
}
}
resize(width, height) {
if (!this.gl) {
return;
}
this._width = width;
this._height = height;
this.canvas.width = this._width * this._pixelRatio;
this.canvas.height = this._height * this._pixelRatio;
this.canvas.style.transform = 'scale('+(1/this._pixelRatio)+') translateZ(0)';
this.gl.viewport(0, 0, this._width* this._pixelRatio , this._height* this._pixelRatio );
}
clearColor(r, g, b, alpha) {
if (!this.gl) {
return;
}
this.gl.clearColor(r, g, b, alpha);
}
clear(color, depth, stencil) {
if (!this.gl) {
return;
}
var bits = 0;
if ( color === void 0 || color ) bits |= this.gl.COLOR_BUFFER_BIT;
if ( depth === void 0 || depth ) bits |= this.gl.DEPTH_BUFFER_BIT;
if ( stencil === void 0 || stencil ) bits |= this.gl.STENCIL_BUFFER_BIT;
this.gl.clear( bits );
}
setPixelRatio(ratio) {
this._pixelRatio = ratio;
this.resize(this._width, this._height);
}
}
export default Renderer;

View File

@@ -1,112 +0,0 @@
import GeometryBuffer from './GeometryBuffer';
import * as vec3 from './glMatrix/vec3';
class SphereGeometryBuffer extends GeometryBuffer {
constructor(gl, options) {
super(gl, 0.);
options = Object.assign({},{
radius: 50,
widthSegments: 8,
heightSegments: 6,
phiStart: 0,
phiLength: Math.PI * 2,
thetaStart: 0,
thetaLength: Math.PI
}, options);
if (!gl) {
return;
}
var radius = options.radius || 50;
var widthSegments = Math.max( 3, Math.floor( options.widthSegments ) || 8 );
var heightSegments = Math.max( 2, Math.floor( options.heightSegments ) || 6 );
var phiStart = phiStart !== undefined ? options.phiStart : 0;
var phiLength = phiLength !== undefined ? options.phiLength : Math.PI * 2;
var thetaStart = thetaStart !== undefined ? options.thetaStart : 0;
var thetaLength = thetaLength !== undefined ? options.thetaLength : Math.PI;
var thetaEnd = thetaStart + thetaLength;
var ix, iy;
var index = 0;
var grid = [];
var vertex = vec3.create();
var normal = vec3.create();
// buffers
var indices = [];
var vertices = [];
var normals = [];
var uvs = [];
var colors = [];
// generate vertices, normals and uvs
for ( iy = 0; iy <= heightSegments; iy ++ ) {
var verticesRow = [];
var v = iy / heightSegments;
for ( ix = 0; ix <= widthSegments; ix ++ ) {
var u = ix / widthSegments;
vertex[0] = - radius * Math.cos( phiStart + u * phiLength ) * Math.sin( thetaStart + v * thetaLength );
vertex[1] = radius * Math.cos( thetaStart + v * thetaLength );
vertex[2] = radius * Math.sin( phiStart + u * phiLength ) * Math.sin( thetaStart + v * thetaLength );
vertices.push( vertex[0], vertex[1], vertex[2] );
vec3.set(normal, vertex[0], vertex[1], vertex[2] );
vec3.normalize(normal, normal);
normals.push( normal[0], normal[1], normal[2] );
uvs.push( u, 1 - v );
verticesRow.push( index ++ );
colors.push( 1,1,1 )
}
grid.push( verticesRow );
}
// indices
for ( iy = 0; iy < heightSegments; iy ++ ) {
for ( ix = 0; ix < widthSegments; ix ++ ) {
var a = grid[ iy ][ ix + 1 ];
var b = grid[ iy ][ ix ];
var c = grid[ iy + 1 ][ ix ];
var d = grid[ iy + 1 ][ ix + 1 ];
if ( iy !== 0 || thetaStart > 0 ) indices.push( a, b, d );
if ( iy !== heightSegments - 1 || thetaEnd < Math.PI ) indices.push( b, c, d );
}
}
// build geometry
this.length = vertices.length/3;
this.addAttribute( 'index', new Uint16Array( indices ), 1 );
this.addAttribute( 'position', new Float32Array( vertices ), 3 );
this.addAttribute( 'normal', new Float32Array( normals ), 3 );
this.addAttribute( 'color', new Float32Array( colors ), 3 );
this.addAttribute( 'uv', new Float32Array( uvs ), 2, 'Sphere' );
}
}
export default SphereGeometryBuffer;

View File

@@ -1,245 +0,0 @@
import uuid from './utils/uuid';
import getFilter from './utils/getFilter';
import isPowerOf2 from './utils/isPowerOf2';
var TEXTURE_CACHE = {};
class Texture {
constructor(gl, options) {
if (!gl) {
return;
}
this.options = Object.assign({}, {
format: gl.RGBA,
type: gl.UNSIGNED_BYTE,
width: 1,
height: 1,
linear: true,
mipmap: false,
miplinear: false,
wrapS: gl.CLAMP_TO_EDGE,
wrapT: gl.CLAMP_TO_EDGE,
anisotropy: 0,
flipY: true,
repeat: [1,1]
}, options);
this._uid = uuid();//debug purpose
this.gl = gl;
this.width = this.options.width;
this.height = this.options.height;
this.format = this.options.format;
this.type = this.options.type;
this.flipY = this.options.flipY;
this.repeat = this.options.repeat;
this._anisotropy = this.options.anisotropy;
if (this.type == gl.FLOAT) {
var floatTextures = gl.getExtension('OES_texture_float');
var floatTextureLinearFiltering = gl.getExtension('OES_texture_float_linear');
if (!floatTextures) {
console.warn('trying to create a FrameBuffer of with gl.FLOAT type but there\s no floating point texture support. trying HALF_FLOAT');
this.type = "HALF_FLOAT"
}
}
if (this.type == "HALF_FLOAT") {
var halfFloatTexturesExt = gl.getExtension('OES_texture_half_float');
var halfFloatTextureLinearFiltering = gl.getExtension('OES_texture_half_float_linear');
if (!halfFloatTexturesExt) {
console.warn('trying to create a texture of with gl.HALF_FLOAT type but there\s no half floating point texture support; falling bck to UNSIGNED_BYTE type');
this.type = gl.UNSIGNED_BYTE;
}
else {
this.type = halfFloatTexturesExt.HALF_FLOAT_OES;
this.isHalfFloat = true;
}
}
this._texture = this.gl.createTexture();
gl.bindTexture( gl.TEXTURE_2D, this._texture );
//1x1 pixel default texture
gl.texImage2D(gl.TEXTURE_2D, 0, this.options.format, this.width, this.height, 0, this.options.format, gl.UNSIGNED_BYTE, new Uint8Array([0, 0, 0, 255]));
/**
* add getter and setter to update texture_wrap when this.wrap changes
*/
Object.defineProperty(this, 'wrapS', {
set: (value) => {
this.gl.texParameteri( this.gl.TEXTURE_2D, this.gl.TEXTURE_WRAP_S, value );
}
});
Object.defineProperty(this, 'wrapT', {
set: (value) => {
this.gl.texParameteri( this.gl.TEXTURE_2D, this.gl.TEXTURE_WRAP_T, value );
}
});
//nPOT texture can't repeat
this.wrapS = this.options.wrapS;
this.wrapT = this.options.wrapT;
//nPOT texture cannot mipmap
this.setFilter( this.options.linear, this.options.mipmap, this.options.mipmapLinear );
//unbind texture
gl.bindTexture( gl.TEXTURE_2D, null);
Object.defineProperty(this, 'anisotropy', {
set: (value) => {
this._anisotropy = value
this.updateAnisotropyFilter()
},
get: () => {
return this._anisotropy
}
});
}
updateAnisotropyFilter() {
let gl = this.gl;
if (!gl) {
return;
}
var ext = (
gl.getExtension('EXT_texture_filter_anisotropic') ||
gl.getExtension('MOZ_EXT_texture_filter_anisotropic') ||
gl.getExtension('WEBKIT_EXT_texture_filter_anisotropic')
);
if (ext) {
if (this._anisotropy > 0) {
gl.bindTexture( gl.TEXTURE_2D, this._texture );
var max = gl.getParameter(ext.MAX_TEXTURE_MAX_ANISOTROPY_EXT);
gl.texParameterf(gl.TEXTURE_2D, ext.TEXTURE_MAX_ANISOTROPY_EXT, Math.min(this._anisotropy, max) );
}
}
}
bindImage(img) {
if (!this.gl) {
return;
}
this.width = img.width;
this.height = img.height;
var isPOT = isPowerOf2(img.width) && isPowerOf2(img.height);
this.gl.bindTexture( this.gl.TEXTURE_2D, this._texture);
this.gl.pixelStorei( this.gl.UNPACK_FLIP_Y_WEBGL, this.flipY);
// console.log('BIND2D', img)
this.gl.texImage2D( this.gl.TEXTURE_2D, 0, this.format, this.format, this.type, img);
if (isPOT) {
//nPOT texture cannot mipmap
this.setFilter( this.options.linear, this.options.mipmap, this.options.mipmapLinear );
this.gl.generateMipmap(this.gl.TEXTURE_2D);
}
else {
this.setFilter(this.options.linear, false, false);
this.wrapS = this.gl.CLAMP_TO_EDGE;
this.wrapT = this.gl.CLAMP_TO_EDGE;
}
this.gl.bindTexture( this.gl.TEXTURE_2D, null);
}
bind(unit) {
if (!this.gl) {
return;
}
//unit is sent by the Program and defined by the unfirom order in the shaders;
if (unit !== void 0) {
this.gl.activeTexture( this.gl.TEXTURE0 + (0|unit) );
}
this.gl.bindTexture(this.gl.TEXTURE_2D, this._texture);
}
delete() {
if (this.gl) {
this.gl.deleteTexture( this._texture );
}
this._texture = null;
this.gl = null;
}
/**
* Change the filtering parameters
* @param {boolean} [smooth=false] if true, use LINEAR filtering
* @param {boolean} [mipmap=false] if true, enable mipmaping
* @param {boolean} [miplinear=false] if true, use linear Mipmapping
*/
setFilter(smooth, mipmap, miplinear) {
if (!this.gl) {
return;
}
var gl = this.gl;
var filter = getFilter( !!smooth, !!mipmap, !!miplinear);
gl.bindTexture( gl.TEXTURE_2D, this._texture );
gl.texParameteri( gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, getFilter( !!smooth, false, false ) );
gl.texParameteri( gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, filter );
this.updateAnisotropyFilter()
}
}
Texture.fromUrl = function(gl, url, options) {
var texture = new Texture(gl, options);
// if (TEXTURE_CACHE[url] !== void 0) {
// this.fromImage( gl, TEXTURE_CACHE[url] );
// return;
// }
var img = new Image();
img.onload = ()=>{
img.onload = null;
img.onerror = null;
TEXTURE_CACHE[url] = img;
options && options.loaded && options.loaded()
texture.bindImage(img);
};
img.onerror = ()=>{
img.onload = null;
img.onerror = null;
console.warn('Invalid url provided to Texture.fromUrl() : ' + url);
};
img.src = url;
return texture;
};
Texture.fromImage = function(gl, img, options) {
if (!img.width || !img.height) {
console.warn('Cannot create texture with provided image\n Please make sure the image is loaded before calling Texture.fromImage() or use Texture.fromUrl()', img);
return;
}
var texture = new Texture(gl, options);
texture.bindImage(img);
return texture;
};
export default Texture;

View File

@@ -1,62 +0,0 @@
/* Copyright (c) 2015, Brandon Jones, Colin MacKenzie IV.
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE. */
/**
* Common utilities
* @module glMatrix
*/
// Configuration Constants
export const EPSILON = 0.000001;
export let ARRAY_TYPE = (typeof Float32Array !== 'undefined') ? Float32Array : Array;
export const RANDOM = Math.random;
/**
* Sets the type of array used when creating new vectors and matrices
*
* @param {Type} type Array type, such as Float32Array or Array
*/
export function setMatrixArrayType(type) {
ARRAY_TYPE = type;
}
const degree = Math.PI / 180;
/**
* Convert Degree To Radian
*
* @param {Number} a Angle in Degrees
*/
export function toRadian(a) {
return a * degree;
}
/**
* Tests whether or not the arguments have approximately the same value, within an absolute
* or relative tolerance of glMatrix.EPSILON (an absolute tolerance is used for values less
* than or equal to 1.0, and a relative tolerance is used for larger values)
*
* @param {Number} a The first number to test.
* @param {Number} b The second number to test.
* @returns {Boolean} True if the numbers are approximately equal, false otherwise.
*/
export function equals(a, b) {
return Math.abs(a - b) <= EPSILON*Math.max(1.0, Math.abs(a), Math.abs(b));
}

View File

@@ -1,433 +0,0 @@
/* Copyright (c) 2015, Brandon Jones, Colin MacKenzie IV.
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE. */
import * as glMatrix from "./common"
/**
* 2x2 Matrix
* @module mat2
*/
/**
* Creates a new identity mat2
*
* @returns {mat2} a new 2x2 matrix
*/
export function create() {
let out = new glMatrix.ARRAY_TYPE(4);
out[0] = 1;
out[1] = 0;
out[2] = 0;
out[3] = 1;
return out;
}
/**
* Creates a new mat2 initialized with values from an existing matrix
*
* @param {mat2} a matrix to clone
* @returns {mat2} a new 2x2 matrix
*/
export function clone(a) {
let out = new glMatrix.ARRAY_TYPE(4);
out[0] = a[0];
out[1] = a[1];
out[2] = a[2];
out[3] = a[3];
return out;
}
/**
* Copy the values from one mat2 to another
*
* @param {mat2} out the receiving matrix
* @param {mat2} a the source matrix
* @returns {mat2} out
*/
export function copy(out, a) {
out[0] = a[0];
out[1] = a[1];
out[2] = a[2];
out[3] = a[3];
return out;
}
/**
* Set a mat2 to the identity matrix
*
* @param {mat2} out the receiving matrix
* @returns {mat2} out
*/
export function identity(out) {
out[0] = 1;
out[1] = 0;
out[2] = 0;
out[3] = 1;
return out;
}
/**
* Create a new mat2 with the given values
*
* @param {Number} m00 Component in column 0, row 0 position (index 0)
* @param {Number} m01 Component in column 0, row 1 position (index 1)
* @param {Number} m10 Component in column 1, row 0 position (index 2)
* @param {Number} m11 Component in column 1, row 1 position (index 3)
* @returns {mat2} out A new 2x2 matrix
*/
export function fromValues(m00, m01, m10, m11) {
let out = new glMatrix.ARRAY_TYPE(4);
out[0] = m00;
out[1] = m01;
out[2] = m10;
out[3] = m11;
return out;
}
/**
* Set the components of a mat2 to the given values
*
* @param {mat2} out the receiving matrix
* @param {Number} m00 Component in column 0, row 0 position (index 0)
* @param {Number} m01 Component in column 0, row 1 position (index 1)
* @param {Number} m10 Component in column 1, row 0 position (index 2)
* @param {Number} m11 Component in column 1, row 1 position (index 3)
* @returns {mat2} out
*/
export function set(out, m00, m01, m10, m11) {
out[0] = m00;
out[1] = m01;
out[2] = m10;
out[3] = m11;
return out;
}
/**
* Transpose the values of a mat2
*
* @param {mat2} out the receiving matrix
* @param {mat2} a the source matrix
* @returns {mat2} out
*/
export function transpose(out, a) {
// If we are transposing ourselves we can skip a few steps but have to cache
// some values
if (out === a) {
let a1 = a[1];
out[1] = a[2];
out[2] = a1;
} else {
out[0] = a[0];
out[1] = a[2];
out[2] = a[1];
out[3] = a[3];
}
return out;
}
/**
* Inverts a mat2
*
* @param {mat2} out the receiving matrix
* @param {mat2} a the source matrix
* @returns {mat2} out
*/
export function invert(out, a) {
let a0 = a[0], a1 = a[1], a2 = a[2], a3 = a[3];
// Calculate the determinant
let det = a0 * a3 - a2 * a1;
if (!det) {
return null;
}
det = 1.0 / det;
out[0] = a3 * det;
out[1] = -a1 * det;
out[2] = -a2 * det;
out[3] = a0 * det;
return out;
}
/**
* Calculates the adjugate of a mat2
*
* @param {mat2} out the receiving matrix
* @param {mat2} a the source matrix
* @returns {mat2} out
*/
export function adjoint(out, a) {
// Caching this value is nessecary if out == a
let a0 = a[0];
out[0] = a[3];
out[1] = -a[1];
out[2] = -a[2];
out[3] = a0;
return out;
}
/**
* Calculates the determinant of a mat2
*
* @param {mat2} a the source matrix
* @returns {Number} determinant of a
*/
export function determinant(a) {
return a[0] * a[3] - a[2] * a[1];
}
/**
* Multiplies two mat2's
*
* @param {mat2} out the receiving matrix
* @param {mat2} a the first operand
* @param {mat2} b the second operand
* @returns {mat2} out
*/
export function multiply(out, a, b) {
let a0 = a[0], a1 = a[1], a2 = a[2], a3 = a[3];
let b0 = b[0], b1 = b[1], b2 = b[2], b3 = b[3];
out[0] = a0 * b0 + a2 * b1;
out[1] = a1 * b0 + a3 * b1;
out[2] = a0 * b2 + a2 * b3;
out[3] = a1 * b2 + a3 * b3;
return out;
}
/**
* Rotates a mat2 by the given angle
*
* @param {mat2} out the receiving matrix
* @param {mat2} a the matrix to rotate
* @param {Number} rad the angle to rotate the matrix by
* @returns {mat2} out
*/
export function rotate(out, a, rad) {
let a0 = a[0], a1 = a[1], a2 = a[2], a3 = a[3];
let s = Math.sin(rad);
let c = Math.cos(rad);
out[0] = a0 * c + a2 * s;
out[1] = a1 * c + a3 * s;
out[2] = a0 * -s + a2 * c;
out[3] = a1 * -s + a3 * c;
return out;
}
/**
* Scales the mat2 by the dimensions in the given vec2
*
* @param {mat2} out the receiving matrix
* @param {mat2} a the matrix to rotate
* @param {vec2} v the vec2 to scale the matrix by
* @returns {mat2} out
**/
export function scale(out, a, v) {
let a0 = a[0], a1 = a[1], a2 = a[2], a3 = a[3];
let v0 = v[0], v1 = v[1];
out[0] = a0 * v0;
out[1] = a1 * v0;
out[2] = a2 * v1;
out[3] = a3 * v1;
return out;
}
/**
* Creates a matrix from a given angle
* This is equivalent to (but much faster than):
*
* mat2.identity(dest);
* mat2.rotate(dest, dest, rad);
*
* @param {mat2} out mat2 receiving operation result
* @param {Number} rad the angle to rotate the matrix by
* @returns {mat2} out
*/
export function fromRotation(out, rad) {
let s = Math.sin(rad);
let c = Math.cos(rad);
out[0] = c;
out[1] = s;
out[2] = -s;
out[3] = c;
return out;
}
/**
* Creates a matrix from a vector scaling
* This is equivalent to (but much faster than):
*
* mat2.identity(dest);
* mat2.scale(dest, dest, vec);
*
* @param {mat2} out mat2 receiving operation result
* @param {vec2} v Scaling vector
* @returns {mat2} out
*/
export function fromScaling(out, v) {
out[0] = v[0];
out[1] = 0;
out[2] = 0;
out[3] = v[1];
return out;
}
/**
* Returns a string representation of a mat2
*
* @param {mat2} a matrix to represent as a string
* @returns {String} string representation of the matrix
*/
export function str(a) {
return 'mat2(' + a[0] + ', ' + a[1] + ', ' + a[2] + ', ' + a[3] + ')';
}
/**
* Returns Frobenius norm of a mat2
*
* @param {mat2} a the matrix to calculate Frobenius norm of
* @returns {Number} Frobenius norm
*/
export function frob(a) {
return(Math.sqrt(Math.pow(a[0], 2) + Math.pow(a[1], 2) + Math.pow(a[2], 2) + Math.pow(a[3], 2)))
}
/**
* Returns L, D and U matrices (Lower triangular, Diagonal and Upper triangular) by factorizing the input matrix
* @param {mat2} L the lower triangular matrix
* @param {mat2} D the diagonal matrix
* @param {mat2} U the upper triangular matrix
* @param {mat2} a the input matrix to factorize
*/
export function LDU(L, D, U, a) {
L[2] = a[2]/a[0];
U[0] = a[0];
U[1] = a[1];
U[3] = a[3] - L[2] * U[1];
return [L, D, U];
}
/**
* Adds two mat2's
*
* @param {mat2} out the receiving matrix
* @param {mat2} a the first operand
* @param {mat2} b the second operand
* @returns {mat2} out
*/
export function add(out, a, b) {
out[0] = a[0] + b[0];
out[1] = a[1] + b[1];
out[2] = a[2] + b[2];
out[3] = a[3] + b[3];
return out;
}
/**
* Subtracts matrix b from matrix a
*
* @param {mat2} out the receiving matrix
* @param {mat2} a the first operand
* @param {mat2} b the second operand
* @returns {mat2} out
*/
export function subtract(out, a, b) {
out[0] = a[0] - b[0];
out[1] = a[1] - b[1];
out[2] = a[2] - b[2];
out[3] = a[3] - b[3];
return out;
}
/**
* Returns whether or not the matrices have exactly the same elements in the same position (when compared with ===)
*
* @param {mat2} a The first matrix.
* @param {mat2} b The second matrix.
* @returns {Boolean} True if the matrices are equal, false otherwise.
*/
export function exactEquals(a, b) {
return a[0] === b[0] && a[1] === b[1] && a[2] === b[2] && a[3] === b[3];
}
/**
* Returns whether or not the matrices have approximately the same elements in the same position.
*
* @param {mat2} a The first matrix.
* @param {mat2} b The second matrix.
* @returns {Boolean} True if the matrices are equal, false otherwise.
*/
export function equals(a, b) {
let a0 = a[0], a1 = a[1], a2 = a[2], a3 = a[3];
let b0 = b[0], b1 = b[1], b2 = b[2], b3 = b[3];
return (Math.abs(a0 - b0) <= glMatrix.EPSILON*Math.max(1.0, Math.abs(a0), Math.abs(b0)) &&
Math.abs(a1 - b1) <= glMatrix.EPSILON*Math.max(1.0, Math.abs(a1), Math.abs(b1)) &&
Math.abs(a2 - b2) <= glMatrix.EPSILON*Math.max(1.0, Math.abs(a2), Math.abs(b2)) &&
Math.abs(a3 - b3) <= glMatrix.EPSILON*Math.max(1.0, Math.abs(a3), Math.abs(b3)));
}
/**
* Multiply each element of the matrix by a scalar.
*
* @param {mat2} out the receiving matrix
* @param {mat2} a the matrix to scale
* @param {Number} b amount to scale the matrix's elements by
* @returns {mat2} out
*/
export function multiplyScalar(out, a, b) {
out[0] = a[0] * b;
out[1] = a[1] * b;
out[2] = a[2] * b;
out[3] = a[3] * b;
return out;
}
/**
* Adds two mat2's after multiplying each element of the second operand by a scalar value.
*
* @param {mat2} out the receiving vector
* @param {mat2} a the first operand
* @param {mat2} b the second operand
* @param {Number} scale the amount to scale b's elements by before adding
* @returns {mat2} out
*/
export function multiplyScalarAndAdd(out, a, b, scale) {
out[0] = a[0] + (b[0] * scale);
out[1] = a[1] + (b[1] * scale);
out[2] = a[2] + (b[2] * scale);
out[3] = a[3] + (b[3] * scale);
return out;
}
/**
* Alias for {@link mat2.multiply}
* @function
*/
export const mul = multiply;
/**
* Alias for {@link mat2.subtract}
* @function
*/
export const sub = subtract;

View File

@@ -1,466 +0,0 @@
/* Copyright (c) 2015, Brandon Jones, Colin MacKenzie IV.
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE. */
import * as glMatrix from "./common";
/**
* 2x3 Matrix
* @module mat2d
*
* @description
* A mat2d contains six elements defined as:
* <pre>
* [a, c, tx,
* b, d, ty]
* </pre>
* This is a short form for the 3x3 matrix:
* <pre>
* [a, c, tx,
* b, d, ty,
* 0, 0, 1]
* </pre>
* The last row is ignored so the array is shorter and operations are faster.
*/
/**
* Creates a new identity mat2d
*
* @returns {mat2d} a new 2x3 matrix
*/
export function create() {
let out = new glMatrix.ARRAY_TYPE(6);
out[0] = 1;
out[1] = 0;
out[2] = 0;
out[3] = 1;
out[4] = 0;
out[5] = 0;
return out;
}
/**
* Creates a new mat2d initialized with values from an existing matrix
*
* @param {mat2d} a matrix to clone
* @returns {mat2d} a new 2x3 matrix
*/
export function clone(a) {
let out = new glMatrix.ARRAY_TYPE(6);
out[0] = a[0];
out[1] = a[1];
out[2] = a[2];
out[3] = a[3];
out[4] = a[4];
out[5] = a[5];
return out;
}
/**
* Copy the values from one mat2d to another
*
* @param {mat2d} out the receiving matrix
* @param {mat2d} a the source matrix
* @returns {mat2d} out
*/
export function copy(out, a) {
out[0] = a[0];
out[1] = a[1];
out[2] = a[2];
out[3] = a[3];
out[4] = a[4];
out[5] = a[5];
return out;
}
/**
* Set a mat2d to the identity matrix
*
* @param {mat2d} out the receiving matrix
* @returns {mat2d} out
*/
export function identity(out) {
out[0] = 1;
out[1] = 0;
out[2] = 0;
out[3] = 1;
out[4] = 0;
out[5] = 0;
return out;
}
/**
* Create a new mat2d with the given values
*
* @param {Number} a Component A (index 0)
* @param {Number} b Component B (index 1)
* @param {Number} c Component C (index 2)
* @param {Number} d Component D (index 3)
* @param {Number} tx Component TX (index 4)
* @param {Number} ty Component TY (index 5)
* @returns {mat2d} A new mat2d
*/
export function fromValues(a, b, c, d, tx, ty) {
let out = new glMatrix.ARRAY_TYPE(6);
out[0] = a;
out[1] = b;
out[2] = c;
out[3] = d;
out[4] = tx;
out[5] = ty;
return out;
}
/**
* Set the components of a mat2d to the given values
*
* @param {mat2d} out the receiving matrix
* @param {Number} a Component A (index 0)
* @param {Number} b Component B (index 1)
* @param {Number} c Component C (index 2)
* @param {Number} d Component D (index 3)
* @param {Number} tx Component TX (index 4)
* @param {Number} ty Component TY (index 5)
* @returns {mat2d} out
*/
export function set(out, a, b, c, d, tx, ty) {
out[0] = a;
out[1] = b;
out[2] = c;
out[3] = d;
out[4] = tx;
out[5] = ty;
return out;
}
/**
* Inverts a mat2d
*
* @param {mat2d} out the receiving matrix
* @param {mat2d} a the source matrix
* @returns {mat2d} out
*/
export function invert(out, a) {
let aa = a[0], ab = a[1], ac = a[2], ad = a[3];
let atx = a[4], aty = a[5];
let det = aa * ad - ab * ac;
if(!det){
return null;
}
det = 1.0 / det;
out[0] = ad * det;
out[1] = -ab * det;
out[2] = -ac * det;
out[3] = aa * det;
out[4] = (ac * aty - ad * atx) * det;
out[5] = (ab * atx - aa * aty) * det;
return out;
}
/**
* Calculates the determinant of a mat2d
*
* @param {mat2d} a the source matrix
* @returns {Number} determinant of a
*/
export function determinant(a) {
return a[0] * a[3] - a[1] * a[2];
}
/**
* Multiplies two mat2d's
*
* @param {mat2d} out the receiving matrix
* @param {mat2d} a the first operand
* @param {mat2d} b the second operand
* @returns {mat2d} out
*/
export function multiply(out, a, b) {
let a0 = a[0], a1 = a[1], a2 = a[2], a3 = a[3], a4 = a[4], a5 = a[5];
let b0 = b[0], b1 = b[1], b2 = b[2], b3 = b[3], b4 = b[4], b5 = b[5];
out[0] = a0 * b0 + a2 * b1;
out[1] = a1 * b0 + a3 * b1;
out[2] = a0 * b2 + a2 * b3;
out[3] = a1 * b2 + a3 * b3;
out[4] = a0 * b4 + a2 * b5 + a4;
out[5] = a1 * b4 + a3 * b5 + a5;
return out;
}
/**
* Rotates a mat2d by the given angle
*
* @param {mat2d} out the receiving matrix
* @param {mat2d} a the matrix to rotate
* @param {Number} rad the angle to rotate the matrix by
* @returns {mat2d} out
*/
export function rotate(out, a, rad) {
let a0 = a[0], a1 = a[1], a2 = a[2], a3 = a[3], a4 = a[4], a5 = a[5];
let s = Math.sin(rad);
let c = Math.cos(rad);
out[0] = a0 * c + a2 * s;
out[1] = a1 * c + a3 * s;
out[2] = a0 * -s + a2 * c;
out[3] = a1 * -s + a3 * c;
out[4] = a4;
out[5] = a5;
return out;
}
/**
* Scales the mat2d by the dimensions in the given vec2
*
* @param {mat2d} out the receiving matrix
* @param {mat2d} a the matrix to translate
* @param {vec2} v the vec2 to scale the matrix by
* @returns {mat2d} out
**/
export function scale(out, a, v) {
let a0 = a[0], a1 = a[1], a2 = a[2], a3 = a[3], a4 = a[4], a5 = a[5];
let v0 = v[0], v1 = v[1];
out[0] = a0 * v0;
out[1] = a1 * v0;
out[2] = a2 * v1;
out[3] = a3 * v1;
out[4] = a4;
out[5] = a5;
return out;
}
/**
* Translates the mat2d by the dimensions in the given vec2
*
* @param {mat2d} out the receiving matrix
* @param {mat2d} a the matrix to translate
* @param {vec2} v the vec2 to translate the matrix by
* @returns {mat2d} out
**/
export function translate(out, a, v) {
let a0 = a[0], a1 = a[1], a2 = a[2], a3 = a[3], a4 = a[4], a5 = a[5];
let v0 = v[0], v1 = v[1];
out[0] = a0;
out[1] = a1;
out[2] = a2;
out[3] = a3;
out[4] = a0 * v0 + a2 * v1 + a4;
out[5] = a1 * v0 + a3 * v1 + a5;
return out;
}
/**
* Creates a matrix from a given angle
* This is equivalent to (but much faster than):
*
* mat2d.identity(dest);
* mat2d.rotate(dest, dest, rad);
*
* @param {mat2d} out mat2d receiving operation result
* @param {Number} rad the angle to rotate the matrix by
* @returns {mat2d} out
*/
export function fromRotation(out, rad) {
let s = Math.sin(rad), c = Math.cos(rad);
out[0] = c;
out[1] = s;
out[2] = -s;
out[3] = c;
out[4] = 0;
out[5] = 0;
return out;
}
/**
* Creates a matrix from a vector scaling
* This is equivalent to (but much faster than):
*
* mat2d.identity(dest);
* mat2d.scale(dest, dest, vec);
*
* @param {mat2d} out mat2d receiving operation result
* @param {vec2} v Scaling vector
* @returns {mat2d} out
*/
export function fromScaling(out, v) {
out[0] = v[0];
out[1] = 0;
out[2] = 0;
out[3] = v[1];
out[4] = 0;
out[5] = 0;
return out;
}
/**
* Creates a matrix from a vector translation
* This is equivalent to (but much faster than):
*
* mat2d.identity(dest);
* mat2d.translate(dest, dest, vec);
*
* @param {mat2d} out mat2d receiving operation result
* @param {vec2} v Translation vector
* @returns {mat2d} out
*/
export function fromTranslation(out, v) {
out[0] = 1;
out[1] = 0;
out[2] = 0;
out[3] = 1;
out[4] = v[0];
out[5] = v[1];
return out;
}
/**
* Returns a string representation of a mat2d
*
* @param {mat2d} a matrix to represent as a string
* @returns {String} string representation of the matrix
*/
export function str(a) {
return 'mat2d(' + a[0] + ', ' + a[1] + ', ' + a[2] + ', ' +
a[3] + ', ' + a[4] + ', ' + a[5] + ')';
}
/**
* Returns Frobenius norm of a mat2d
*
* @param {mat2d} a the matrix to calculate Frobenius norm of
* @returns {Number} Frobenius norm
*/
export function frob(a) {
return(Math.sqrt(Math.pow(a[0], 2) + Math.pow(a[1], 2) + Math.pow(a[2], 2) + Math.pow(a[3], 2) + Math.pow(a[4], 2) + Math.pow(a[5], 2) + 1))
}
/**
* Adds two mat2d's
*
* @param {mat2d} out the receiving matrix
* @param {mat2d} a the first operand
* @param {mat2d} b the second operand
* @returns {mat2d} out
*/
export function add(out, a, b) {
out[0] = a[0] + b[0];
out[1] = a[1] + b[1];
out[2] = a[2] + b[2];
out[3] = a[3] + b[3];
out[4] = a[4] + b[4];
out[5] = a[5] + b[5];
return out;
}
/**
* Subtracts matrix b from matrix a
*
* @param {mat2d} out the receiving matrix
* @param {mat2d} a the first operand
* @param {mat2d} b the second operand
* @returns {mat2d} out
*/
export function subtract(out, a, b) {
out[0] = a[0] - b[0];
out[1] = a[1] - b[1];
out[2] = a[2] - b[2];
out[3] = a[3] - b[3];
out[4] = a[4] - b[4];
out[5] = a[5] - b[5];
return out;
}
/**
* Multiply each element of the matrix by a scalar.
*
* @param {mat2d} out the receiving matrix
* @param {mat2d} a the matrix to scale
* @param {Number} b amount to scale the matrix's elements by
* @returns {mat2d} out
*/
export function multiplyScalar(out, a, b) {
out[0] = a[0] * b;
out[1] = a[1] * b;
out[2] = a[2] * b;
out[3] = a[3] * b;
out[4] = a[4] * b;
out[5] = a[5] * b;
return out;
}
/**
* Adds two mat2d's after multiplying each element of the second operand by a scalar value.
*
* @param {mat2d} out the receiving vector
* @param {mat2d} a the first operand
* @param {mat2d} b the second operand
* @param {Number} scale the amount to scale b's elements by before adding
* @returns {mat2d} out
*/
export function multiplyScalarAndAdd(out, a, b, scale) {
out[0] = a[0] + (b[0] * scale);
out[1] = a[1] + (b[1] * scale);
out[2] = a[2] + (b[2] * scale);
out[3] = a[3] + (b[3] * scale);
out[4] = a[4] + (b[4] * scale);
out[5] = a[5] + (b[5] * scale);
return out;
}
/**
* Returns whether or not the matrices have exactly the same elements in the same position (when compared with ===)
*
* @param {mat2d} a The first matrix.
* @param {mat2d} b The second matrix.
* @returns {Boolean} True if the matrices are equal, false otherwise.
*/
export function exactEquals(a, b) {
return a[0] === b[0] && a[1] === b[1] && a[2] === b[2] && a[3] === b[3] && a[4] === b[4] && a[5] === b[5];
}
/**
* Returns whether or not the matrices have approximately the same elements in the same position.
*
* @param {mat2d} a The first matrix.
* @param {mat2d} b The second matrix.
* @returns {Boolean} True if the matrices are equal, false otherwise.
*/
export function equals(a, b) {
let a0 = a[0], a1 = a[1], a2 = a[2], a3 = a[3], a4 = a[4], a5 = a[5];
let b0 = b[0], b1 = b[1], b2 = b[2], b3 = b[3], b4 = b[4], b5 = b[5];
return (Math.abs(a0 - b0) <= glMatrix.EPSILON*Math.max(1.0, Math.abs(a0), Math.abs(b0)) &&
Math.abs(a1 - b1) <= glMatrix.EPSILON*Math.max(1.0, Math.abs(a1), Math.abs(b1)) &&
Math.abs(a2 - b2) <= glMatrix.EPSILON*Math.max(1.0, Math.abs(a2), Math.abs(b2)) &&
Math.abs(a3 - b3) <= glMatrix.EPSILON*Math.max(1.0, Math.abs(a3), Math.abs(b3)) &&
Math.abs(a4 - b4) <= glMatrix.EPSILON*Math.max(1.0, Math.abs(a4), Math.abs(b4)) &&
Math.abs(a5 - b5) <= glMatrix.EPSILON*Math.max(1.0, Math.abs(a5), Math.abs(b5)));
}
/**
* Alias for {@link mat2d.multiply}
* @function
*/
export const mul = multiply;
/**
* Alias for {@link mat2d.subtract}
* @function
*/
export const sub = subtract;

View File

@@ -1,765 +0,0 @@
/* Copyright (c) 2015, Brandon Jones, Colin MacKenzie IV.
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE. */
import * as glMatrix from "./common";
/**
* 3x3 Matrix
* @module mat3
*/
/**
* Creates a new identity mat3
*
* @returns {mat3} a new 3x3 matrix
*/
export function create() {
let out = new glMatrix.ARRAY_TYPE(9);
out[0] = 1;
out[1] = 0;
out[2] = 0;
out[3] = 0;
out[4] = 1;
out[5] = 0;
out[6] = 0;
out[7] = 0;
out[8] = 1;
return out;
}
/**
* Copies the upper-left 3x3 values into the given mat3.
*
* @param {mat3} out the receiving 3x3 matrix
* @param {mat4} a the source 4x4 matrix
* @returns {mat3} out
*/
export function fromMat4(out, a) {
out[0] = a[0];
out[1] = a[1];
out[2] = a[2];
out[3] = a[4];
out[4] = a[5];
out[5] = a[6];
out[6] = a[8];
out[7] = a[9];
out[8] = a[10];
return out;
}
/**
* Creates a new mat3 initialized with values from an existing matrix
*
* @param {mat3} a matrix to clone
* @returns {mat3} a new 3x3 matrix
*/
export function clone(a) {
let out = new glMatrix.ARRAY_TYPE(9);
out[0] = a[0];
out[1] = a[1];
out[2] = a[2];
out[3] = a[3];
out[4] = a[4];
out[5] = a[5];
out[6] = a[6];
out[7] = a[7];
out[8] = a[8];
return out;
}
/**
* Copy the values from one mat3 to another
*
* @param {mat3} out the receiving matrix
* @param {mat3} a the source matrix
* @returns {mat3} out
*/
export function copy(out, a) {
out[0] = a[0];
out[1] = a[1];
out[2] = a[2];
out[3] = a[3];
out[4] = a[4];
out[5] = a[5];
out[6] = a[6];
out[7] = a[7];
out[8] = a[8];
return out;
}
/**
* Create a new mat3 with the given values
*
* @param {Number} m00 Component in column 0, row 0 position (index 0)
* @param {Number} m01 Component in column 0, row 1 position (index 1)
* @param {Number} m02 Component in column 0, row 2 position (index 2)
* @param {Number} m10 Component in column 1, row 0 position (index 3)
* @param {Number} m11 Component in column 1, row 1 position (index 4)
* @param {Number} m12 Component in column 1, row 2 position (index 5)
* @param {Number} m20 Component in column 2, row 0 position (index 6)
* @param {Number} m21 Component in column 2, row 1 position (index 7)
* @param {Number} m22 Component in column 2, row 2 position (index 8)
* @returns {mat3} A new mat3
*/
export function fromValues(m00, m01, m02, m10, m11, m12, m20, m21, m22) {
let out = new glMatrix.ARRAY_TYPE(9);
out[0] = m00;
out[1] = m01;
out[2] = m02;
out[3] = m10;
out[4] = m11;
out[5] = m12;
out[6] = m20;
out[7] = m21;
out[8] = m22;
return out;
}
/**
* Set the components of a mat3 to the given values
*
* @param {mat3} out the receiving matrix
* @param {Number} m00 Component in column 0, row 0 position (index 0)
* @param {Number} m01 Component in column 0, row 1 position (index 1)
* @param {Number} m02 Component in column 0, row 2 position (index 2)
* @param {Number} m10 Component in column 1, row 0 position (index 3)
* @param {Number} m11 Component in column 1, row 1 position (index 4)
* @param {Number} m12 Component in column 1, row 2 position (index 5)
* @param {Number} m20 Component in column 2, row 0 position (index 6)
* @param {Number} m21 Component in column 2, row 1 position (index 7)
* @param {Number} m22 Component in column 2, row 2 position (index 8)
* @returns {mat3} out
*/
export function set(out, m00, m01, m02, m10, m11, m12, m20, m21, m22) {
out[0] = m00;
out[1] = m01;
out[2] = m02;
out[3] = m10;
out[4] = m11;
out[5] = m12;
out[6] = m20;
out[7] = m21;
out[8] = m22;
return out;
}
/**
* Set a mat3 to the identity matrix
*
* @param {mat3} out the receiving matrix
* @returns {mat3} out
*/
export function identity(out) {
out[0] = 1;
out[1] = 0;
out[2] = 0;
out[3] = 0;
out[4] = 1;
out[5] = 0;
out[6] = 0;
out[7] = 0;
out[8] = 1;
return out;
}
/**
* Transpose the values of a mat3
*
* @param {mat3} out the receiving matrix
* @param {mat3} a the source matrix
* @returns {mat3} out
*/
export function transpose(out, a) {
// If we are transposing ourselves we can skip a few steps but have to cache some values
if (out === a) {
let a01 = a[1], a02 = a[2], a12 = a[5];
out[1] = a[3];
out[2] = a[6];
out[3] = a01;
out[5] = a[7];
out[6] = a02;
out[7] = a12;
} else {
out[0] = a[0];
out[1] = a[3];
out[2] = a[6];
out[3] = a[1];
out[4] = a[4];
out[5] = a[7];
out[6] = a[2];
out[7] = a[5];
out[8] = a[8];
}
return out;
}
/**
* Inverts a mat3
*
* @param {mat3} out the receiving matrix
* @param {mat3} a the source matrix
* @returns {mat3} out
*/
export function invert(out, a) {
let a00 = a[0], a01 = a[1], a02 = a[2];
let a10 = a[3], a11 = a[4], a12 = a[5];
let a20 = a[6], a21 = a[7], a22 = a[8];
let b01 = a22 * a11 - a12 * a21;
let b11 = -a22 * a10 + a12 * a20;
let b21 = a21 * a10 - a11 * a20;
// Calculate the determinant
let det = a00 * b01 + a01 * b11 + a02 * b21;
if (!det) {
return null;
}
det = 1.0 / det;
out[0] = b01 * det;
out[1] = (-a22 * a01 + a02 * a21) * det;
out[2] = (a12 * a01 - a02 * a11) * det;
out[3] = b11 * det;
out[4] = (a22 * a00 - a02 * a20) * det;
out[5] = (-a12 * a00 + a02 * a10) * det;
out[6] = b21 * det;
out[7] = (-a21 * a00 + a01 * a20) * det;
out[8] = (a11 * a00 - a01 * a10) * det;
return out;
}
/**
* Calculates the adjugate of a mat3
*
* @param {mat3} out the receiving matrix
* @param {mat3} a the source matrix
* @returns {mat3} out
*/
export function adjoint(out, a) {
let a00 = a[0], a01 = a[1], a02 = a[2];
let a10 = a[3], a11 = a[4], a12 = a[5];
let a20 = a[6], a21 = a[7], a22 = a[8];
out[0] = (a11 * a22 - a12 * a21);
out[1] = (a02 * a21 - a01 * a22);
out[2] = (a01 * a12 - a02 * a11);
out[3] = (a12 * a20 - a10 * a22);
out[4] = (a00 * a22 - a02 * a20);
out[5] = (a02 * a10 - a00 * a12);
out[6] = (a10 * a21 - a11 * a20);
out[7] = (a01 * a20 - a00 * a21);
out[8] = (a00 * a11 - a01 * a10);
return out;
}
/**
* Calculates the determinant of a mat3
*
* @param {mat3} a the source matrix
* @returns {Number} determinant of a
*/
export function determinant(a) {
let a00 = a[0], a01 = a[1], a02 = a[2];
let a10 = a[3], a11 = a[4], a12 = a[5];
let a20 = a[6], a21 = a[7], a22 = a[8];
return a00 * (a22 * a11 - a12 * a21) + a01 * (-a22 * a10 + a12 * a20) + a02 * (a21 * a10 - a11 * a20);
}
/**
* Multiplies two mat3's
*
* @param {mat3} out the receiving matrix
* @param {mat3} a the first operand
* @param {mat3} b the second operand
* @returns {mat3} out
*/
export function multiply(out, a, b) {
let a00 = a[0], a01 = a[1], a02 = a[2];
let a10 = a[3], a11 = a[4], a12 = a[5];
let a20 = a[6], a21 = a[7], a22 = a[8];
let b00 = b[0], b01 = b[1], b02 = b[2];
let b10 = b[3], b11 = b[4], b12 = b[5];
let b20 = b[6], b21 = b[7], b22 = b[8];
out[0] = b00 * a00 + b01 * a10 + b02 * a20;
out[1] = b00 * a01 + b01 * a11 + b02 * a21;
out[2] = b00 * a02 + b01 * a12 + b02 * a22;
out[3] = b10 * a00 + b11 * a10 + b12 * a20;
out[4] = b10 * a01 + b11 * a11 + b12 * a21;
out[5] = b10 * a02 + b11 * a12 + b12 * a22;
out[6] = b20 * a00 + b21 * a10 + b22 * a20;
out[7] = b20 * a01 + b21 * a11 + b22 * a21;
out[8] = b20 * a02 + b21 * a12 + b22 * a22;
return out;
}
/**
* Translate a mat3 by the given vector
*
* @param {mat3} out the receiving matrix
* @param {mat3} a the matrix to translate
* @param {vec2} v vector to translate by
* @returns {mat3} out
*/
export function translate(out, a, v) {
let a00 = a[0], a01 = a[1], a02 = a[2],
a10 = a[3], a11 = a[4], a12 = a[5],
a20 = a[6], a21 = a[7], a22 = a[8],
x = v[0], y = v[1];
out[0] = a00;
out[1] = a01;
out[2] = a02;
out[3] = a10;
out[4] = a11;
out[5] = a12;
out[6] = x * a00 + y * a10 + a20;
out[7] = x * a01 + y * a11 + a21;
out[8] = x * a02 + y * a12 + a22;
return out;
}
/**
* Rotates a mat3 by the given angle
*
* @param {mat3} out the receiving matrix
* @param {mat3} a the matrix to rotate
* @param {Number} rad the angle to rotate the matrix by
* @returns {mat3} out
*/
export function rotate(out, a, rad) {
let a00 = a[0], a01 = a[1], a02 = a[2],
a10 = a[3], a11 = a[4], a12 = a[5],
a20 = a[6], a21 = a[7], a22 = a[8],
s = Math.sin(rad),
c = Math.cos(rad);
out[0] = c * a00 + s * a10;
out[1] = c * a01 + s * a11;
out[2] = c * a02 + s * a12;
out[3] = c * a10 - s * a00;
out[4] = c * a11 - s * a01;
out[5] = c * a12 - s * a02;
out[6] = a20;
out[7] = a21;
out[8] = a22;
return out;
};
/**
* Scales the mat3 by the dimensions in the given vec2
*
* @param {mat3} out the receiving matrix
* @param {mat3} a the matrix to rotate
* @param {vec2} v the vec2 to scale the matrix by
* @returns {mat3} out
**/
export function scale(out, a, v) {
let x = v[0], y = v[1];
out[0] = x * a[0];
out[1] = x * a[1];
out[2] = x * a[2];
out[3] = y * a[3];
out[4] = y * a[4];
out[5] = y * a[5];
out[6] = a[6];
out[7] = a[7];
out[8] = a[8];
return out;
}
/**
* Creates a matrix from a vector translation
* This is equivalent to (but much faster than):
*
* mat3.identity(dest);
* mat3.translate(dest, dest, vec);
*
* @param {mat3} out mat3 receiving operation result
* @param {vec2} v Translation vector
* @returns {mat3} out
*/
export function fromTranslation(out, v) {
out[0] = 1;
out[1] = 0;
out[2] = 0;
out[3] = 0;
out[4] = 1;
out[5] = 0;
out[6] = v[0];
out[7] = v[1];
out[8] = 1;
return out;
}
/**
* Creates a matrix from a given angle
* This is equivalent to (but much faster than):
*
* mat3.identity(dest);
* mat3.rotate(dest, dest, rad);
*
* @param {mat3} out mat3 receiving operation result
* @param {Number} rad the angle to rotate the matrix by
* @returns {mat3} out
*/
export function fromRotation(out, rad) {
let s = Math.sin(rad), c = Math.cos(rad);
out[0] = c;
out[1] = s;
out[2] = 0;
out[3] = -s;
out[4] = c;
out[5] = 0;
out[6] = 0;
out[7] = 0;
out[8] = 1;
return out;
}
/**
* Creates a matrix from a vector scaling
* This is equivalent to (but much faster than):
*
* mat3.identity(dest);
* mat3.scale(dest, dest, vec);
*
* @param {mat3} out mat3 receiving operation result
* @param {vec2} v Scaling vector
* @returns {mat3} out
*/
export function fromScaling(out, v) {
out[0] = v[0];
out[1] = 0;
out[2] = 0;
out[3] = 0;
out[4] = v[1];
out[5] = 0;
out[6] = 0;
out[7] = 0;
out[8] = 1;
return out;
}
/**
* Copies the values from a mat2d into a mat3
*
* @param {mat3} out the receiving matrix
* @param {mat2d} a the matrix to copy
* @returns {mat3} out
**/
export function fromMat2d(out, a) {
out[0] = a[0];
out[1] = a[1];
out[2] = 0;
out[3] = a[2];
out[4] = a[3];
out[5] = 0;
out[6] = a[4];
out[7] = a[5];
out[8] = 1;
return out;
}
/**
* Calculates a 3x3 matrix from the given quaternion
*
* @param {mat3} out mat3 receiving operation result
* @param {quat} q Quaternion to create matrix from
*
* @returns {mat3} out
*/
export function fromQuat(out, q) {
let x = q[0], y = q[1], z = q[2], w = q[3];
let x2 = x + x;
let y2 = y + y;
let z2 = z + z;
let xx = x * x2;
let yx = y * x2;
let yy = y * y2;
let zx = z * x2;
let zy = z * y2;
let zz = z * z2;
let wx = w * x2;
let wy = w * y2;
let wz = w * z2;
out[0] = 1 - yy - zz;
out[3] = yx - wz;
out[6] = zx + wy;
out[1] = yx + wz;
out[4] = 1 - xx - zz;
out[7] = zy - wx;
out[2] = zx - wy;
out[5] = zy + wx;
out[8] = 1 - xx - yy;
return out;
}
/**
* Calculates a 3x3 normal matrix (transpose inverse) from the 4x4 matrix
*
* @param {mat3} out mat3 receiving operation result
* @param {mat4} a Mat4 to derive the normal matrix from
*
* @returns {mat3} out
*/
export function normalFromMat4(out, a) {
let a00 = a[0], a01 = a[1], a02 = a[2], a03 = a[3];
let a10 = a[4], a11 = a[5], a12 = a[6], a13 = a[7];
let a20 = a[8], a21 = a[9], a22 = a[10], a23 = a[11];
let a30 = a[12], a31 = a[13], a32 = a[14], a33 = a[15];
let b00 = a00 * a11 - a01 * a10;
let b01 = a00 * a12 - a02 * a10;
let b02 = a00 * a13 - a03 * a10;
let b03 = a01 * a12 - a02 * a11;
let b04 = a01 * a13 - a03 * a11;
let b05 = a02 * a13 - a03 * a12;
let b06 = a20 * a31 - a21 * a30;
let b07 = a20 * a32 - a22 * a30;
let b08 = a20 * a33 - a23 * a30;
let b09 = a21 * a32 - a22 * a31;
let b10 = a21 * a33 - a23 * a31;
let b11 = a22 * a33 - a23 * a32;
// Calculate the determinant
let det = b00 * b11 - b01 * b10 + b02 * b09 + b03 * b08 - b04 * b07 + b05 * b06;
if (!det) {
return null;
}
det = 1.0 / det;
out[0] = (a11 * b11 - a12 * b10 + a13 * b09) * det;
out[1] = (a12 * b08 - a10 * b11 - a13 * b07) * det;
out[2] = (a10 * b10 - a11 * b08 + a13 * b06) * det;
out[3] = (a02 * b10 - a01 * b11 - a03 * b09) * det;
out[4] = (a00 * b11 - a02 * b08 + a03 * b07) * det;
out[5] = (a01 * b08 - a00 * b10 - a03 * b06) * det;
out[6] = (a31 * b05 - a32 * b04 + a33 * b03) * det;
out[7] = (a32 * b02 - a30 * b05 - a33 * b01) * det;
out[8] = (a30 * b04 - a31 * b02 + a33 * b00) * det;
return out;
}
/**
* Generates a 2D projection matrix with the given bounds
*
* @param {mat3} out mat3 frustum matrix will be written into
* @param {number} width Width of your gl context
* @param {number} height Height of gl context
* @returns {mat3} out
*/
export function projection(out, width, height) {
out[0] = 2 / width;
out[1] = 0;
out[2] = 0;
out[3] = 0;
out[4] = -2 / height;
out[5] = 0;
out[6] = -1;
out[7] = 1;
out[8] = 1;
return out;
}
/**
* Returns a string representation of a mat3
*
* @param {mat3} a matrix to represent as a string
* @returns {String} string representation of the matrix
*/
export function str(a) {
return 'mat3(' + a[0] + ', ' + a[1] + ', ' + a[2] + ', ' +
a[3] + ', ' + a[4] + ', ' + a[5] + ', ' +
a[6] + ', ' + a[7] + ', ' + a[8] + ')';
}
/**
* Returns Frobenius norm of a mat3
*
* @param {mat3} a the matrix to calculate Frobenius norm of
* @returns {Number} Frobenius norm
*/
export function frob(a) {
return(Math.sqrt(Math.pow(a[0], 2) + Math.pow(a[1], 2) + Math.pow(a[2], 2) + Math.pow(a[3], 2) + Math.pow(a[4], 2) + Math.pow(a[5], 2) + Math.pow(a[6], 2) + Math.pow(a[7], 2) + Math.pow(a[8], 2)))
}
/**
* Adds two mat3's
*
* @param {mat3} out the receiving matrix
* @param {mat3} a the first operand
* @param {mat3} b the second operand
* @returns {mat3} out
*/
export function add(out, a, b) {
out[0] = a[0] + b[0];
out[1] = a[1] + b[1];
out[2] = a[2] + b[2];
out[3] = a[3] + b[3];
out[4] = a[4] + b[4];
out[5] = a[5] + b[5];
out[6] = a[6] + b[6];
out[7] = a[7] + b[7];
out[8] = a[8] + b[8];
return out;
}
/**
* Subtracts matrix b from matrix a
*
* @param {mat3} out the receiving matrix
* @param {mat3} a the first operand
* @param {mat3} b the second operand
* @returns {mat3} out
*/
export function subtract(out, a, b) {
out[0] = a[0] - b[0];
out[1] = a[1] - b[1];
out[2] = a[2] - b[2];
out[3] = a[3] - b[3];
out[4] = a[4] - b[4];
out[5] = a[5] - b[5];
out[6] = a[6] - b[6];
out[7] = a[7] - b[7];
out[8] = a[8] - b[8];
return out;
}
/**
* Multiply each element of the matrix by a scalar.
*
* @param {mat3} out the receiving matrix
* @param {mat3} a the matrix to scale
* @param {Number} b amount to scale the matrix's elements by
* @returns {mat3} out
*/
export function multiplyScalar(out, a, b) {
out[0] = a[0] * b;
out[1] = a[1] * b;
out[2] = a[2] * b;
out[3] = a[3] * b;
out[4] = a[4] * b;
out[5] = a[5] * b;
out[6] = a[6] * b;
out[7] = a[7] * b;
out[8] = a[8] * b;
return out;
}
/**
* Adds two mat3's after multiplying each element of the second operand by a scalar value.
*
* @param {mat3} out the receiving vector
* @param {mat3} a the first operand
* @param {mat3} b the second operand
* @param {Number} scale the amount to scale b's elements by before adding
* @returns {mat3} out
*/
export function multiplyScalarAndAdd(out, a, b, scale) {
out[0] = a[0] + (b[0] * scale);
out[1] = a[1] + (b[1] * scale);
out[2] = a[2] + (b[2] * scale);
out[3] = a[3] + (b[3] * scale);
out[4] = a[4] + (b[4] * scale);
out[5] = a[5] + (b[5] * scale);
out[6] = a[6] + (b[6] * scale);
out[7] = a[7] + (b[7] * scale);
out[8] = a[8] + (b[8] * scale);
return out;
}
/**
* Returns whether or not the matrices have exactly the same elements in the same position (when compared with ===)
*
* @param {mat3} a The first matrix.
* @param {mat3} b The second matrix.
* @returns {Boolean} True if the matrices are equal, false otherwise.
*/
export function exactEquals(a, b) {
return a[0] === b[0] && a[1] === b[1] && a[2] === b[2] &&
a[3] === b[3] && a[4] === b[4] && a[5] === b[5] &&
a[6] === b[6] && a[7] === b[7] && a[8] === b[8];
}
/**
* Returns whether or not the matrices have approximately the same elements in the same position.
*
* @param {mat3} a The first matrix.
* @param {mat3} b The second matrix.
* @returns {Boolean} True if the matrices are equal, false otherwise.
*/
export function equals(a, b) {
let a0 = a[0], a1 = a[1], a2 = a[2], a3 = a[3], a4 = a[4], a5 = a[5], a6 = a[6], a7 = a[7], a8 = a[8];
let b0 = b[0], b1 = b[1], b2 = b[2], b3 = b[3], b4 = b[4], b5 = b[5], b6 = b[6], b7 = b[7], b8 = b[8];
return (Math.abs(a0 - b0) <= glMatrix.EPSILON*Math.max(1.0, Math.abs(a0), Math.abs(b0)) &&
Math.abs(a1 - b1) <= glMatrix.EPSILON*Math.max(1.0, Math.abs(a1), Math.abs(b1)) &&
Math.abs(a2 - b2) <= glMatrix.EPSILON*Math.max(1.0, Math.abs(a2), Math.abs(b2)) &&
Math.abs(a3 - b3) <= glMatrix.EPSILON*Math.max(1.0, Math.abs(a3), Math.abs(b3)) &&
Math.abs(a4 - b4) <= glMatrix.EPSILON*Math.max(1.0, Math.abs(a4), Math.abs(b4)) &&
Math.abs(a5 - b5) <= glMatrix.EPSILON*Math.max(1.0, Math.abs(a5), Math.abs(b5)) &&
Math.abs(a6 - b6) <= glMatrix.EPSILON*Math.max(1.0, Math.abs(a6), Math.abs(b6)) &&
Math.abs(a7 - b7) <= glMatrix.EPSILON*Math.max(1.0, Math.abs(a7), Math.abs(b7)) &&
Math.abs(a8 - b8) <= glMatrix.EPSILON*Math.max(1.0, Math.abs(a8), Math.abs(b8)));
}
/**
* Alias for {@link mat3.multiply}
* @function
*/
export const mul = multiply;
/**
* Alias for {@link mat3.subtract}
* @function
*/
export const sub = subtract;

File diff suppressed because it is too large Load Diff

View File

@@ -1,626 +0,0 @@
/* Copyright (c) 2015, Brandon Jones, Colin MacKenzie IV.
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE. */
import * as glMatrix from "./common"
import * as mat3 from "./mat3"
import * as vec3 from "./vec3"
import * as vec4 from "./vec4"
/**
* Quaternion
* @module quat
*/
/**
* Creates a new identity quat
*
* @returns {quat} a new quaternion
*/
export function create() {
let out = new glMatrix.ARRAY_TYPE(4);
out[0] = 0;
out[1] = 0;
out[2] = 0;
out[3] = 1;
return out;
}
/**
* Set a quat to the identity quaternion
*
* @param {quat} out the receiving quaternion
* @returns {quat} out
*/
export function identity(out) {
out[0] = 0;
out[1] = 0;
out[2] = 0;
out[3] = 1;
return out;
}
/**
* Sets a quat from the given angle and rotation axis,
* then returns it.
*
* @param {quat} out the receiving quaternion
* @param {vec3} axis the axis around which to rotate
* @param {Number} rad the angle in radians
* @returns {quat} out
**/
export function setAxisAngle(out, axis, rad) {
rad = rad * 0.5;
let s = Math.sin(rad);
out[0] = s * axis[0];
out[1] = s * axis[1];
out[2] = s * axis[2];
out[3] = Math.cos(rad);
return out;
}
/**
* Gets the rotation axis and angle for a given
* quaternion. If a quaternion is created with
* setAxisAngle, this method will return the same
* values as providied in the original parameter list
* OR functionally equivalent values.
* Example: The quaternion formed by axis [0, 0, 1] and
* angle -90 is the same as the quaternion formed by
* [0, 0, 1] and 270. This method favors the latter.
* @param {vec3} out_axis Vector receiving the axis of rotation
* @param {quat} q Quaternion to be decomposed
* @return {Number} Angle, in radians, of the rotation
*/
export function getAxisAngle(out_axis, q) {
let rad = Math.acos(q[3]) * 2.0;
let s = Math.sin(rad / 2.0);
if (s != 0.0) {
out_axis[0] = q[0] / s;
out_axis[1] = q[1] / s;
out_axis[2] = q[2] / s;
} else {
// If s is zero, return any axis (no rotation - axis does not matter)
out_axis[0] = 1;
out_axis[1] = 0;
out_axis[2] = 0;
}
return rad;
}
/**
* Multiplies two quat's
*
* @param {quat} out the receiving quaternion
* @param {quat} a the first operand
* @param {quat} b the second operand
* @returns {quat} out
*/
export function multiply(out, a, b) {
let ax = a[0], ay = a[1], az = a[2], aw = a[3];
let bx = b[0], by = b[1], bz = b[2], bw = b[3];
out[0] = ax * bw + aw * bx + ay * bz - az * by;
out[1] = ay * bw + aw * by + az * bx - ax * bz;
out[2] = az * bw + aw * bz + ax * by - ay * bx;
out[3] = aw * bw - ax * bx - ay * by - az * bz;
return out;
}
/**
* Rotates a quaternion by the given angle about the X axis
*
* @param {quat} out quat receiving operation result
* @param {quat} a quat to rotate
* @param {number} rad angle (in radians) to rotate
* @returns {quat} out
*/
export function rotateX(out, a, rad) {
rad *= 0.5;
let ax = a[0], ay = a[1], az = a[2], aw = a[3];
let bx = Math.sin(rad), bw = Math.cos(rad);
out[0] = ax * bw + aw * bx;
out[1] = ay * bw + az * bx;
out[2] = az * bw - ay * bx;
out[3] = aw * bw - ax * bx;
return out;
}
/**
* Rotates a quaternion by the given angle about the Y axis
*
* @param {quat} out quat receiving operation result
* @param {quat} a quat to rotate
* @param {number} rad angle (in radians) to rotate
* @returns {quat} out
*/
export function rotateY(out, a, rad) {
rad *= 0.5;
let ax = a[0], ay = a[1], az = a[2], aw = a[3];
let by = Math.sin(rad), bw = Math.cos(rad);
out[0] = ax * bw - az * by;
out[1] = ay * bw + aw * by;
out[2] = az * bw + ax * by;
out[3] = aw * bw - ay * by;
return out;
}
/**
* Rotates a quaternion by the given angle about the Z axis
*
* @param {quat} out quat receiving operation result
* @param {quat} a quat to rotate
* @param {number} rad angle (in radians) to rotate
* @returns {quat} out
*/
export function rotateZ(out, a, rad) {
rad *= 0.5;
let ax = a[0], ay = a[1], az = a[2], aw = a[3];
let bz = Math.sin(rad), bw = Math.cos(rad);
out[0] = ax * bw + ay * bz;
out[1] = ay * bw - ax * bz;
out[2] = az * bw + aw * bz;
out[3] = aw * bw - az * bz;
return out;
}
/**
* Calculates the W component of a quat from the X, Y, and Z components.
* Assumes that quaternion is 1 unit in length.
* Any existing W component will be ignored.
*
* @param {quat} out the receiving quaternion
* @param {quat} a quat to calculate W component of
* @returns {quat} out
*/
export function calculateW(out, a) {
let x = a[0], y = a[1], z = a[2];
out[0] = x;
out[1] = y;
out[2] = z;
out[3] = Math.sqrt(Math.abs(1.0 - x * x - y * y - z * z));
return out;
}
/**
* Performs a spherical linear interpolation between two quat
*
* @param {quat} out the receiving quaternion
* @param {quat} a the first operand
* @param {quat} b the second operand
* @param {Number} t interpolation amount between the two inputs
* @returns {quat} out
*/
export function slerp(out, a, b, t) {
// benchmarks:
// http://jsperf.com/quaternion-slerp-implementations
let ax = a[0], ay = a[1], az = a[2], aw = a[3];
let bx = b[0], by = b[1], bz = b[2], bw = b[3];
let omega, cosom, sinom, scale0, scale1;
// calc cosine
cosom = ax * bx + ay * by + az * bz + aw * bw;
// adjust signs (if necessary)
if ( cosom < 0.0 ) {
cosom = -cosom;
bx = - bx;
by = - by;
bz = - bz;
bw = - bw;
}
// calculate coefficients
if ( (1.0 - cosom) > 0.000001 ) {
// standard case (slerp)
omega = Math.acos(cosom);
sinom = Math.sin(omega);
scale0 = Math.sin((1.0 - t) * omega) / sinom;
scale1 = Math.sin(t * omega) / sinom;
} else {
// "from" and "to" quaternions are very close
// ... so we can do a linear interpolation
scale0 = 1.0 - t;
scale1 = t;
}
// calculate final values
out[0] = scale0 * ax + scale1 * bx;
out[1] = scale0 * ay + scale1 * by;
out[2] = scale0 * az + scale1 * bz;
out[3] = scale0 * aw + scale1 * bw;
return out;
}
/**
* Calculates the inverse of a quat
*
* @param {quat} out the receiving quaternion
* @param {quat} a quat to calculate inverse of
* @returns {quat} out
*/
export function invert(out, a) {
let a0 = a[0], a1 = a[1], a2 = a[2], a3 = a[3];
let dot = a0*a0 + a1*a1 + a2*a2 + a3*a3;
let invDot = dot ? 1.0/dot : 0;
// TODO: Would be faster to return [0,0,0,0] immediately if dot == 0
out[0] = -a0*invDot;
out[1] = -a1*invDot;
out[2] = -a2*invDot;
out[3] = a3*invDot;
return out;
}
/**
* Calculates the conjugate of a quat
* If the quaternion is normalized, this function is faster than quat.inverse and produces the same result.
*
* @param {quat} out the receiving quaternion
* @param {quat} a quat to calculate conjugate of
* @returns {quat} out
*/
export function conjugate(out, a) {
out[0] = -a[0];
out[1] = -a[1];
out[2] = -a[2];
out[3] = a[3];
return out;
}
/**
* Creates a quaternion from the given 3x3 rotation matrix.
*
* NOTE: The resultant quaternion is not normalized, so you should be sure
* to renormalize the quaternion yourself where necessary.
*
* @param {quat} out the receiving quaternion
* @param {mat3} m rotation matrix
* @returns {quat} out
* @function
*/
export function fromMat3(out, m) {
// Algorithm in Ken Shoemake's article in 1987 SIGGRAPH course notes
// article "Quaternion Calculus and Fast Animation".
let fTrace = m[0] + m[4] + m[8];
let fRoot;
if ( fTrace > 0.0 ) {
// |w| > 1/2, may as well choose w > 1/2
fRoot = Math.sqrt(fTrace + 1.0); // 2w
out[3] = 0.5 * fRoot;
fRoot = 0.5/fRoot; // 1/(4w)
out[0] = (m[5]-m[7])*fRoot;
out[1] = (m[6]-m[2])*fRoot;
out[2] = (m[1]-m[3])*fRoot;
} else {
// |w| <= 1/2
let i = 0;
if ( m[4] > m[0] )
i = 1;
if ( m[8] > m[i*3+i] )
i = 2;
let j = (i+1)%3;
let k = (i+2)%3;
fRoot = Math.sqrt(m[i*3+i]-m[j*3+j]-m[k*3+k] + 1.0);
out[i] = 0.5 * fRoot;
fRoot = 0.5 / fRoot;
out[3] = (m[j*3+k] - m[k*3+j]) * fRoot;
out[j] = (m[j*3+i] + m[i*3+j]) * fRoot;
out[k] = (m[k*3+i] + m[i*3+k]) * fRoot;
}
return out;
}
/**
* Creates a quaternion from the given euler angle x, y, z.
*
* @param {quat} out the receiving quaternion
* @param {x} Angle to rotate around X axis in degrees.
* @param {y} Angle to rotate around Y axis in degrees.
* @param {z} Angle to rotate around Z axis in degrees.
* @returns {quat} out
* @function
*/
export function fromEuler(out, x, y, z) {
let halfToRad = 0.5 * Math.PI / 180.0;
x *= halfToRad;
y *= halfToRad;
z *= halfToRad;
let sx = Math.sin(x);
let cx = Math.cos(x);
let sy = Math.sin(y);
let cy = Math.cos(y);
let sz = Math.sin(z);
let cz = Math.cos(z);
out[0] = sx * cy * cz - cx * sy * sz;
out[1] = cx * sy * cz + sx * cy * sz;
out[2] = cx * cy * sz - sx * sy * cz;
out[3] = cx * cy * cz + sx * sy * sz;
return out;
}
/**
* Returns a string representation of a quatenion
*
* @param {quat} a vector to represent as a string
* @returns {String} string representation of the vector
*/
export function str(a) {
return 'quat(' + a[0] + ', ' + a[1] + ', ' + a[2] + ', ' + a[3] + ')';
}
/**
* Creates a new quat initialized with values from an existing quaternion
*
* @param {quat} a quaternion to clone
* @returns {quat} a new quaternion
* @function
*/
export const clone = vec4.clone;
/**
* Creates a new quat initialized with the given values
*
* @param {Number} x X component
* @param {Number} y Y component
* @param {Number} z Z component
* @param {Number} w W component
* @returns {quat} a new quaternion
* @function
*/
export const fromValues = vec4.fromValues;
/**
* Copy the values from one quat to another
*
* @param {quat} out the receiving quaternion
* @param {quat} a the source quaternion
* @returns {quat} out
* @function
*/
export const copy = vec4.copy;
/**
* Set the components of a quat to the given values
*
* @param {quat} out the receiving quaternion
* @param {Number} x X component
* @param {Number} y Y component
* @param {Number} z Z component
* @param {Number} w W component
* @returns {quat} out
* @function
*/
export const set = vec4.set;
/**
* Adds two quat's
*
* @param {quat} out the receiving quaternion
* @param {quat} a the first operand
* @param {quat} b the second operand
* @returns {quat} out
* @function
*/
export const add = vec4.add;
/**
* Alias for {@link quat.multiply}
* @function
*/
export const mul = multiply;
/**
* Scales a quat by a scalar number
*
* @param {quat} out the receiving vector
* @param {quat} a the vector to scale
* @param {Number} b amount to scale the vector by
* @returns {quat} out
* @function
*/
export const scale = vec4.scale;
/**
* Calculates the dot product of two quat's
*
* @param {quat} a the first operand
* @param {quat} b the second operand
* @returns {Number} dot product of a and b
* @function
*/
export const dot = vec4.dot;
/**
* Performs a linear interpolation between two quat's
*
* @param {quat} out the receiving quaternion
* @param {quat} a the first operand
* @param {quat} b the second operand
* @param {Number} t interpolation amount between the two inputs
* @returns {quat} out
* @function
*/
export const lerp = vec4.lerp;
/**
* Calculates the length of a quat
*
* @param {quat} a vector to calculate length of
* @returns {Number} length of a
*/
export const length = vec4.length;
/**
* Alias for {@link quat.length}
* @function
*/
export const len = length;
/**
* Calculates the squared length of a quat
*
* @param {quat} a vector to calculate squared length of
* @returns {Number} squared length of a
* @function
*/
export const squaredLength = vec4.squaredLength;
/**
* Alias for {@link quat.squaredLength}
* @function
*/
export const sqrLen = squaredLength;
/**
* Normalize a quat
*
* @param {quat} out the receiving quaternion
* @param {quat} a quaternion to normalize
* @returns {quat} out
* @function
*/
export const normalize = vec4.normalize;
/**
* Returns whether or not the quaternions have exactly the same elements in the same position (when compared with ===)
*
* @param {quat} a The first quaternion.
* @param {quat} b The second quaternion.
* @returns {Boolean} True if the vectors are equal, false otherwise.
*/
export const exactEquals = vec4.exactEquals;
/**
* Returns whether or not the quaternions have approximately the same elements in the same position.
*
* @param {quat} a The first vector.
* @param {quat} b The second vector.
* @returns {Boolean} True if the vectors are equal, false otherwise.
*/
export const equals = vec4.equals;
/**
* Sets a quaternion to represent the shortest rotation from one
* vector to another.
*
* Both vectors are assumed to be unit length.
*
* @param {quat} out the receiving quaternion.
* @param {vec3} a the initial vector
* @param {vec3} b the destination vector
* @returns {quat} out
*/
export const rotationTo = (function() {
let tmpvec3 = vec3.create();
let xUnitVec3 = vec3.fromValues(1,0,0);
let yUnitVec3 = vec3.fromValues(0,1,0);
return function(out, a, b) {
let dot = vec3.dot(a, b);
if (dot < -0.999999) {
vec3.cross(tmpvec3, xUnitVec3, a);
if (vec3.len(tmpvec3) < 0.000001)
vec3.cross(tmpvec3, yUnitVec3, a);
vec3.normalize(tmpvec3, tmpvec3);
setAxisAngle(out, tmpvec3, Math.PI);
return out;
} else if (dot > 0.999999) {
out[0] = 0;
out[1] = 0;
out[2] = 0;
out[3] = 1;
return out;
} else {
vec3.cross(tmpvec3, a, b);
out[0] = tmpvec3[0];
out[1] = tmpvec3[1];
out[2] = tmpvec3[2];
out[3] = 1 + dot;
return normalize(out, out);
}
};
})();
/**
* Performs a spherical linear interpolation with two control points
*
* @param {quat} out the receiving quaternion
* @param {quat} a the first operand
* @param {quat} b the second operand
* @param {quat} c the third operand
* @param {quat} d the fourth operand
* @param {Number} t interpolation amount
* @returns {quat} out
*/
export const sqlerp = (function () {
let temp1 = create();
let temp2 = create();
return function (out, a, b, c, d, t) {
slerp(temp1, a, d, t);
slerp(temp2, b, c, t);
slerp(out, temp1, temp2, 2 * t * (1 - t));
return out;
};
}());
/**
* Sets the specified quaternion with values corresponding to the given
* axes. Each axis is a vec3 and is expected to be unit length and
* perpendicular to all other specified axes.
*
* @param {vec3} view the vector representing the viewing direction
* @param {vec3} right the vector representing the local "right" direction
* @param {vec3} up the vector representing the local "up" direction
* @returns {quat} out
*/
export const setAxes = (function() {
let matr = mat3.create();
return function(out, view, right, up) {
matr[0] = right[0];
matr[3] = right[1];
matr[6] = right[2];
matr[1] = up[0];
matr[4] = up[1];
matr[7] = up[2];
matr[2] = -view[0];
matr[5] = -view[1];
matr[8] = -view[2];
return normalize(out, fromMat3(out, matr));
};
})();

View File

@@ -1,584 +0,0 @@
/* Copyright (c) 2015, Brandon Jones, Colin MacKenzie IV.
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE. */
import * as glMatrix from "./common";
/**
* 2 Dimensional Vector
* @module vec2
*/
/**
* Creates a new, empty vec2
*
* @returns {vec2} a new 2D vector
*/
export function create() {
let out = new glMatrix.ARRAY_TYPE(2);
out[0] = 0;
out[1] = 0;
return out;
}
/**
* Creates a new vec2 initialized with values from an existing vector
*
* @param {vec2} a vector to clone
* @returns {vec2} a new 2D vector
*/
export function clone(a) {
let out = new glMatrix.ARRAY_TYPE(2);
out[0] = a[0];
out[1] = a[1];
return out;
}
/**
* Creates a new vec2 initialized with the given values
*
* @param {Number} x X component
* @param {Number} y Y component
* @returns {vec2} a new 2D vector
*/
export function fromValues(x, y) {
let out = new glMatrix.ARRAY_TYPE(2);
out[0] = x;
out[1] = y;
return out;
}
/**
* Copy the values from one vec2 to another
*
* @param {vec2} out the receiving vector
* @param {vec2} a the source vector
* @returns {vec2} out
*/
export function copy(out, a) {
out[0] = a[0];
out[1] = a[1];
return out;
}
/**
* Set the components of a vec2 to the given values
*
* @param {vec2} out the receiving vector
* @param {Number} x X component
* @param {Number} y Y component
* @returns {vec2} out
*/
export function set(out, x, y) {
out[0] = x;
out[1] = y;
return out;
}
/**
* Adds two vec2's
*
* @param {vec2} out the receiving vector
* @param {vec2} a the first operand
* @param {vec2} b the second operand
* @returns {vec2} out
*/
export function add(out, a, b) {
out[0] = a[0] + b[0];
out[1] = a[1] + b[1];
return out;
}
/**
* Subtracts vector b from vector a
*
* @param {vec2} out the receiving vector
* @param {vec2} a the first operand
* @param {vec2} b the second operand
* @returns {vec2} out
*/
export function subtract(out, a, b) {
out[0] = a[0] - b[0];
out[1] = a[1] - b[1];
return out;
}
/**
* Multiplies two vec2's
*
* @param {vec2} out the receiving vector
* @param {vec2} a the first operand
* @param {vec2} b the second operand
* @returns {vec2} out
*/
export function multiply(out, a, b) {
out[0] = a[0] * b[0];
out[1] = a[1] * b[1];
return out;
};
/**
* Divides two vec2's
*
* @param {vec2} out the receiving vector
* @param {vec2} a the first operand
* @param {vec2} b the second operand
* @returns {vec2} out
*/
export function divide(out, a, b) {
out[0] = a[0] / b[0];
out[1] = a[1] / b[1];
return out;
};
/**
* Math.ceil the components of a vec2
*
* @param {vec2} out the receiving vector
* @param {vec2} a vector to ceil
* @returns {vec2} out
*/
export function ceil(out, a) {
out[0] = Math.ceil(a[0]);
out[1] = Math.ceil(a[1]);
return out;
};
/**
* Math.floor the components of a vec2
*
* @param {vec2} out the receiving vector
* @param {vec2} a vector to floor
* @returns {vec2} out
*/
export function floor(out, a) {
out[0] = Math.floor(a[0]);
out[1] = Math.floor(a[1]);
return out;
};
/**
* Returns the minimum of two vec2's
*
* @param {vec2} out the receiving vector
* @param {vec2} a the first operand
* @param {vec2} b the second operand
* @returns {vec2} out
*/
export function min(out, a, b) {
out[0] = Math.min(a[0], b[0]);
out[1] = Math.min(a[1], b[1]);
return out;
};
/**
* Returns the maximum of two vec2's
*
* @param {vec2} out the receiving vector
* @param {vec2} a the first operand
* @param {vec2} b the second operand
* @returns {vec2} out
*/
export function max(out, a, b) {
out[0] = Math.max(a[0], b[0]);
out[1] = Math.max(a[1], b[1]);
return out;
};
/**
* Math.round the components of a vec2
*
* @param {vec2} out the receiving vector
* @param {vec2} a vector to round
* @returns {vec2} out
*/
export function round (out, a) {
out[0] = Math.round(a[0]);
out[1] = Math.round(a[1]);
return out;
};
/**
* Scales a vec2 by a scalar number
*
* @param {vec2} out the receiving vector
* @param {vec2} a the vector to scale
* @param {Number} b amount to scale the vector by
* @returns {vec2} out
*/
export function scale(out, a, b) {
out[0] = a[0] * b;
out[1] = a[1] * b;
return out;
};
/**
* Adds two vec2's after scaling the second operand by a scalar value
*
* @param {vec2} out the receiving vector
* @param {vec2} a the first operand
* @param {vec2} b the second operand
* @param {Number} scale the amount to scale b by before adding
* @returns {vec2} out
*/
export function scaleAndAdd(out, a, b, scale) {
out[0] = a[0] + (b[0] * scale);
out[1] = a[1] + (b[1] * scale);
return out;
};
/**
* Calculates the euclidian distance between two vec2's
*
* @param {vec2} a the first operand
* @param {vec2} b the second operand
* @returns {Number} distance between a and b
*/
export function distance(a, b) {
var x = b[0] - a[0],
y = b[1] - a[1];
return Math.sqrt(x*x + y*y);
};
/**
* Calculates the squared euclidian distance between two vec2's
*
* @param {vec2} a the first operand
* @param {vec2} b the second operand
* @returns {Number} squared distance between a and b
*/
export function squaredDistance(a, b) {
var x = b[0] - a[0],
y = b[1] - a[1];
return x*x + y*y;
};
/**
* Calculates the length of a vec2
*
* @param {vec2} a vector to calculate length of
* @returns {Number} length of a
*/
export function length(a) {
var x = a[0],
y = a[1];
return Math.sqrt(x*x + y*y);
};
/**
* Calculates the squared length of a vec2
*
* @param {vec2} a vector to calculate squared length of
* @returns {Number} squared length of a
*/
export function squaredLength (a) {
var x = a[0],
y = a[1];
return x*x + y*y;
};
/**
* Negates the components of a vec2
*
* @param {vec2} out the receiving vector
* @param {vec2} a vector to negate
* @returns {vec2} out
*/
export function negate(out, a) {
out[0] = -a[0];
out[1] = -a[1];
return out;
};
/**
* Returns the inverse of the components of a vec2
*
* @param {vec2} out the receiving vector
* @param {vec2} a vector to invert
* @returns {vec2} out
*/
export function inverse(out, a) {
out[0] = 1.0 / a[0];
out[1] = 1.0 / a[1];
return out;
};
/**
* Normalize a vec2
*
* @param {vec2} out the receiving vector
* @param {vec2} a vector to normalize
* @returns {vec2} out
*/
export function normalize(out, a) {
var x = a[0],
y = a[1];
var len = x*x + y*y;
if (len > 0) {
//TODO: evaluate use of glm_invsqrt here?
len = 1 / Math.sqrt(len);
out[0] = a[0] * len;
out[1] = a[1] * len;
}
return out;
};
/**
* Calculates the dot product of two vec2's
*
* @param {vec2} a the first operand
* @param {vec2} b the second operand
* @returns {Number} dot product of a and b
*/
export function dot(a, b) {
return a[0] * b[0] + a[1] * b[1];
};
/**
* Computes the cross product of two vec2's
* Note that the cross product must by definition produce a 3D vector
*
* @param {vec3} out the receiving vector
* @param {vec2} a the first operand
* @param {vec2} b the second operand
* @returns {vec3} out
*/
export function cross(out, a, b) {
var z = a[0] * b[1] - a[1] * b[0];
out[0] = out[1] = 0;
out[2] = z;
return out;
};
/**
* Performs a linear interpolation between two vec2's
*
* @param {vec2} out the receiving vector
* @param {vec2} a the first operand
* @param {vec2} b the second operand
* @param {Number} t interpolation amount between the two inputs
* @returns {vec2} out
*/
export function lerp(out, a, b, t) {
var ax = a[0],
ay = a[1];
out[0] = ax + t * (b[0] - ax);
out[1] = ay + t * (b[1] - ay);
return out;
};
/**
* Generates a random vector with the given scale
*
* @param {vec2} out the receiving vector
* @param {Number} [scale] Length of the resulting vector. If ommitted, a unit vector will be returned
* @returns {vec2} out
*/
export function random(out, scale) {
scale = scale || 1.0;
var r = glMatrix.RANDOM() * 2.0 * Math.PI;
out[0] = Math.cos(r) * scale;
out[1] = Math.sin(r) * scale;
return out;
};
/**
* Transforms the vec2 with a mat2
*
* @param {vec2} out the receiving vector
* @param {vec2} a the vector to transform
* @param {mat2} m matrix to transform with
* @returns {vec2} out
*/
export function transformMat2(out, a, m) {
var x = a[0],
y = a[1];
out[0] = m[0] * x + m[2] * y;
out[1] = m[1] * x + m[3] * y;
return out;
};
/**
* Transforms the vec2 with a mat2d
*
* @param {vec2} out the receiving vector
* @param {vec2} a the vector to transform
* @param {mat2d} m matrix to transform with
* @returns {vec2} out
*/
export function transformMat2d(out, a, m) {
var x = a[0],
y = a[1];
out[0] = m[0] * x + m[2] * y + m[4];
out[1] = m[1] * x + m[3] * y + m[5];
return out;
};
/**
* Transforms the vec2 with a mat3
* 3rd vector component is implicitly '1'
*
* @param {vec2} out the receiving vector
* @param {vec2} a the vector to transform
* @param {mat3} m matrix to transform with
* @returns {vec2} out
*/
export function transformMat3(out, a, m) {
var x = a[0],
y = a[1];
out[0] = m[0] * x + m[3] * y + m[6];
out[1] = m[1] * x + m[4] * y + m[7];
return out;
};
/**
* Transforms the vec2 with a mat4
* 3rd vector component is implicitly '0'
* 4th vector component is implicitly '1'
*
* @param {vec2} out the receiving vector
* @param {vec2} a the vector to transform
* @param {mat4} m matrix to transform with
* @returns {vec2} out
*/
export function transformMat4(out, a, m) {
let x = a[0];
let y = a[1];
out[0] = m[0] * x + m[4] * y + m[12];
out[1] = m[1] * x + m[5] * y + m[13];
return out;
}
/**
* Returns a string representation of a vector
*
* @param {vec2} a vector to represent as a string
* @returns {String} string representation of the vector
*/
export function str(a) {
return 'vec2(' + a[0] + ', ' + a[1] + ')';
}
/**
* Returns whether or not the vectors exactly have the same elements in the same position (when compared with ===)
*
* @param {vec2} a The first vector.
* @param {vec2} b The second vector.
* @returns {Boolean} True if the vectors are equal, false otherwise.
*/
export function exactEquals(a, b) {
return a[0] === b[0] && a[1] === b[1];
}
/**
* Returns whether or not the vectors have approximately the same elements in the same position.
*
* @param {vec2} a The first vector.
* @param {vec2} b The second vector.
* @returns {Boolean} True if the vectors are equal, false otherwise.
*/
export function equals(a, b) {
let a0 = a[0], a1 = a[1];
let b0 = b[0], b1 = b[1];
return (Math.abs(a0 - b0) <= glMatrix.EPSILON*Math.max(1.0, Math.abs(a0), Math.abs(b0)) &&
Math.abs(a1 - b1) <= glMatrix.EPSILON*Math.max(1.0, Math.abs(a1), Math.abs(b1)));
}
/**
* Alias for {@link vec2.length}
* @function
*/
export const len = length;
/**
* Alias for {@link vec2.subtract}
* @function
*/
export const sub = subtract;
/**
* Alias for {@link vec2.multiply}
* @function
*/
export const mul = multiply;
/**
* Alias for {@link vec2.divide}
* @function
*/
export const div = divide;
/**
* Alias for {@link vec2.distance}
* @function
*/
export const dist = distance;
/**
* Alias for {@link vec2.squaredDistance}
* @function
*/
export const sqrDist = squaredDistance;
/**
* Alias for {@link vec2.squaredLength}
* @function
*/
export const sqrLen = squaredLength;
/**
* Perform some operation over an array of vec2s.
*
* @param {Array} a the array of vectors to iterate over
* @param {Number} stride Number of elements between the start of each vec2. If 0 assumes tightly packed
* @param {Number} offset Number of elements to skip at the beginning of the array
* @param {Number} count Number of vec2s to iterate over. If 0 iterates over entire array
* @param {Function} fn Function to call for each vector in the array
* @param {Object} [arg] additional argument to pass to fn
* @returns {Array} a
* @function
*/
export const forEach = (function() {
let vec = create();
return function(a, stride, offset, count, fn, arg) {
let i, l;
if(!stride) {
stride = 2;
}
if(!offset) {
offset = 0;
}
if(count) {
l = Math.min((count * stride) + offset, a.length);
} else {
l = a.length;
}
for(i = offset; i < l; i += stride) {
vec[0] = a[i]; vec[1] = a[i+1];
fn(vec, vec, arg);
a[i] = vec[0]; a[i+1] = vec[1];
}
return a;
};
})();

View File

@@ -1,776 +0,0 @@
/* Copyright (c) 2015, Brandon Jones, Colin MacKenzie IV.
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE. */
import * as glMatrix from "./common";
/**
* 3 Dimensional Vector
* @module vec3
*/
/**
* Creates a new, empty vec3
*
* @returns {vec3} a new 3D vector
*/
export function create() {
let out = new glMatrix.ARRAY_TYPE(3);
out[0] = 0;
out[1] = 0;
out[2] = 0;
return out;
}
/**
* Creates a new vec3 initialized with values from an existing vector
*
* @param {vec3} a vector to clone
* @returns {vec3} a new 3D vector
*/
export function clone(a) {
var out = new glMatrix.ARRAY_TYPE(3);
out[0] = a[0];
out[1] = a[1];
out[2] = a[2];
return out;
}
/**
* Calculates the length of a vec3
*
* @param {vec3} a vector to calculate length of
* @returns {Number} length of a
*/
export function length(a) {
let x = a[0];
let y = a[1];
let z = a[2];
return Math.sqrt(x*x + y*y + z*z);
}
/**
* Creates a new vec3 initialized with the given values
*
* @param {Number} x X component
* @param {Number} y Y component
* @param {Number} z Z component
* @returns {vec3} a new 3D vector
*/
export function fromValues(x, y, z) {
let out = new glMatrix.ARRAY_TYPE(3);
out[0] = x;
out[1] = y;
out[2] = z;
return out;
}
/**
* Copy the values from one vec3 to another
*
* @param {vec3} out the receiving vector
* @param {vec3} a the source vector
* @returns {vec3} out
*/
export function copy(out, a) {
out[0] = a[0];
out[1] = a[1];
out[2] = a[2];
return out;
}
/**
* Set the components of a vec3 to the given values
*
* @param {vec3} out the receiving vector
* @param {Number} x X component
* @param {Number} y Y component
* @param {Number} z Z component
* @returns {vec3} out
*/
export function set(out, x, y, z) {
out[0] = x;
out[1] = y;
out[2] = z;
return out;
}
/**
* Adds two vec3's
*
* @param {vec3} out the receiving vector
* @param {vec3} a the first operand
* @param {vec3} b the second operand
* @returns {vec3} out
*/
export function add(out, a, b) {
out[0] = a[0] + b[0];
out[1] = a[1] + b[1];
out[2] = a[2] + b[2];
return out;
}
/**
* Subtracts vector b from vector a
*
* @param {vec3} out the receiving vector
* @param {vec3} a the first operand
* @param {vec3} b the second operand
* @returns {vec3} out
*/
export function subtract(out, a, b) {
out[0] = a[0] - b[0];
out[1] = a[1] - b[1];
out[2] = a[2] - b[2];
return out;
}
/**
* Multiplies two vec3's
*
* @param {vec3} out the receiving vector
* @param {vec3} a the first operand
* @param {vec3} b the second operand
* @returns {vec3} out
*/
export function multiply(out, a, b) {
out[0] = a[0] * b[0];
out[1] = a[1] * b[1];
out[2] = a[2] * b[2];
return out;
}
/**
* Divides two vec3's
*
* @param {vec3} out the receiving vector
* @param {vec3} a the first operand
* @param {vec3} b the second operand
* @returns {vec3} out
*/
export function divide(out, a, b) {
out[0] = a[0] / b[0];
out[1] = a[1] / b[1];
out[2] = a[2] / b[2];
return out;
}
/**
* Math.ceil the components of a vec3
*
* @param {vec3} out the receiving vector
* @param {vec3} a vector to ceil
* @returns {vec3} out
*/
export function ceil(out, a) {
out[0] = Math.ceil(a[0]);
out[1] = Math.ceil(a[1]);
out[2] = Math.ceil(a[2]);
return out;
}
/**
* Math.floor the components of a vec3
*
* @param {vec3} out the receiving vector
* @param {vec3} a vector to floor
* @returns {vec3} out
*/
export function floor(out, a) {
out[0] = Math.floor(a[0]);
out[1] = Math.floor(a[1]);
out[2] = Math.floor(a[2]);
return out;
}
/**
* Returns the minimum of two vec3's
*
* @param {vec3} out the receiving vector
* @param {vec3} a the first operand
* @param {vec3} b the second operand
* @returns {vec3} out
*/
export function min(out, a, b) {
out[0] = Math.min(a[0], b[0]);
out[1] = Math.min(a[1], b[1]);
out[2] = Math.min(a[2], b[2]);
return out;
}
/**
* Returns the maximum of two vec3's
*
* @param {vec3} out the receiving vector
* @param {vec3} a the first operand
* @param {vec3} b the second operand
* @returns {vec3} out
*/
export function max(out, a, b) {
out[0] = Math.max(a[0], b[0]);
out[1] = Math.max(a[1], b[1]);
out[2] = Math.max(a[2], b[2]);
return out;
}
/**
* Math.round the components of a vec3
*
* @param {vec3} out the receiving vector
* @param {vec3} a vector to round
* @returns {vec3} out
*/
export function round(out, a) {
out[0] = Math.round(a[0]);
out[1] = Math.round(a[1]);
out[2] = Math.round(a[2]);
return out;
}
/**
* Scales a vec3 by a scalar number
*
* @param {vec3} out the receiving vector
* @param {vec3} a the vector to scale
* @param {Number} b amount to scale the vector by
* @returns {vec3} out
*/
export function scale(out, a, b) {
out[0] = a[0] * b;
out[1] = a[1] * b;
out[2] = a[2] * b;
return out;
}
/**
* Adds two vec3's after scaling the second operand by a scalar value
*
* @param {vec3} out the receiving vector
* @param {vec3} a the first operand
* @param {vec3} b the second operand
* @param {Number} scale the amount to scale b by before adding
* @returns {vec3} out
*/
export function scaleAndAdd(out, a, b, scale) {
out[0] = a[0] + (b[0] * scale);
out[1] = a[1] + (b[1] * scale);
out[2] = a[2] + (b[2] * scale);
return out;
}
/**
* Calculates the euclidian distance between two vec3's
*
* @param {vec3} a the first operand
* @param {vec3} b the second operand
* @returns {Number} distance between a and b
*/
export function distance(a, b) {
let x = b[0] - a[0];
let y = b[1] - a[1];
let z = b[2] - a[2];
return Math.sqrt(x*x + y*y + z*z);
}
/**
* Calculates the squared euclidian distance between two vec3's
*
* @param {vec3} a the first operand
* @param {vec3} b the second operand
* @returns {Number} squared distance between a and b
*/
export function squaredDistance(a, b) {
let x = b[0] - a[0];
let y = b[1] - a[1];
let z = b[2] - a[2];
return x*x + y*y + z*z;
}
/**
* Calculates the squared length of a vec3
*
* @param {vec3} a vector to calculate squared length of
* @returns {Number} squared length of a
*/
export function squaredLength(a) {
let x = a[0];
let y = a[1];
let z = a[2];
return x*x + y*y + z*z;
}
/**
* Negates the components of a vec3
*
* @param {vec3} out the receiving vector
* @param {vec3} a vector to negate
* @returns {vec3} out
*/
export function negate(out, a) {
out[0] = -a[0];
out[1] = -a[1];
out[2] = -a[2];
return out;
}
/**
* Returns the inverse of the components of a vec3
*
* @param {vec3} out the receiving vector
* @param {vec3} a vector to invert
* @returns {vec3} out
*/
export function inverse(out, a) {
out[0] = 1.0 / a[0];
out[1] = 1.0 / a[1];
out[2] = 1.0 / a[2];
return out;
}
/**
* Normalize a vec3
*
* @param {vec3} out the receiving vector
* @param {vec3} a vector to normalize
* @returns {vec3} out
*/
export function normalize(out, a) {
let x = a[0];
let y = a[1];
let z = a[2];
let len = x*x + y*y + z*z;
if (len > 0) {
//TODO: evaluate use of glm_invsqrt here?
len = 1 / Math.sqrt(len);
out[0] = a[0] * len;
out[1] = a[1] * len;
out[2] = a[2] * len;
}
return out;
}
/**
* Calculates the dot product of two vec3's
*
* @param {vec3} a the first operand
* @param {vec3} b the second operand
* @returns {Number} dot product of a and b
*/
export function dot(a, b) {
return a[0] * b[0] + a[1] * b[1] + a[2] * b[2];
}
/**
* Computes the cross product of two vec3's
*
* @param {vec3} out the receiving vector
* @param {vec3} a the first operand
* @param {vec3} b the second operand
* @returns {vec3} out
*/
export function cross(out, a, b) {
let ax = a[0], ay = a[1], az = a[2];
let bx = b[0], by = b[1], bz = b[2];
out[0] = ay * bz - az * by;
out[1] = az * bx - ax * bz;
out[2] = ax * by - ay * bx;
return out;
}
/**
* Performs a linear interpolation between two vec3's
*
* @param {vec3} out the receiving vector
* @param {vec3} a the first operand
* @param {vec3} b the second operand
* @param {Number} t interpolation amount between the two inputs
* @returns {vec3} out
*/
export function lerp(out, a, b, t) {
let ax = a[0];
let ay = a[1];
let az = a[2];
out[0] = ax + t * (b[0] - ax);
out[1] = ay + t * (b[1] - ay);
out[2] = az + t * (b[2] - az);
return out;
}
/**
* Performs a hermite interpolation with two control points
*
* @param {vec3} out the receiving vector
* @param {vec3} a the first operand
* @param {vec3} b the second operand
* @param {vec3} c the third operand
* @param {vec3} d the fourth operand
* @param {Number} t interpolation amount between the two inputs
* @returns {vec3} out
*/
export function hermite(out, a, b, c, d, t) {
let factorTimes2 = t * t;
let factor1 = factorTimes2 * (2 * t - 3) + 1;
let factor2 = factorTimes2 * (t - 2) + t;
let factor3 = factorTimes2 * (t - 1);
let factor4 = factorTimes2 * (3 - 2 * t);
out[0] = a[0] * factor1 + b[0] * factor2 + c[0] * factor3 + d[0] * factor4;
out[1] = a[1] * factor1 + b[1] * factor2 + c[1] * factor3 + d[1] * factor4;
out[2] = a[2] * factor1 + b[2] * factor2 + c[2] * factor3 + d[2] * factor4;
return out;
}
/**
* Performs a bezier interpolation with two control points
*
* @param {vec3} out the receiving vector
* @param {vec3} a the first operand
* @param {vec3} b the second operand
* @param {vec3} c the third operand
* @param {vec3} d the fourth operand
* @param {Number} t interpolation amount between the two inputs
* @returns {vec3} out
*/
export function bezier(out, a, b, c, d, t) {
let inverseFactor = 1 - t;
let inverseFactorTimesTwo = inverseFactor * inverseFactor;
let factorTimes2 = t * t;
let factor1 = inverseFactorTimesTwo * inverseFactor;
let factor2 = 3 * t * inverseFactorTimesTwo;
let factor3 = 3 * factorTimes2 * inverseFactor;
let factor4 = factorTimes2 * t;
out[0] = a[0] * factor1 + b[0] * factor2 + c[0] * factor3 + d[0] * factor4;
out[1] = a[1] * factor1 + b[1] * factor2 + c[1] * factor3 + d[1] * factor4;
out[2] = a[2] * factor1 + b[2] * factor2 + c[2] * factor3 + d[2] * factor4;
return out;
}
/**
* Generates a random vector with the given scale
*
* @param {vec3} out the receiving vector
* @param {Number} [scale] Length of the resulting vector. If ommitted, a unit vector will be returned
* @returns {vec3} out
*/
export function random(out, scale) {
scale = scale || 1.0;
let r = glMatrix.RANDOM() * 2.0 * Math.PI;
let z = (glMatrix.RANDOM() * 2.0) - 1.0;
let zScale = Math.sqrt(1.0-z*z) * scale;
out[0] = Math.cos(r) * zScale;
out[1] = Math.sin(r) * zScale;
out[2] = z * scale;
return out;
}
/**
* Transforms the vec3 with a mat4.
* 4th vector component is implicitly '1'
*
* @param {vec3} out the receiving vector
* @param {vec3} a the vector to transform
* @param {mat4} m matrix to transform with
* @returns {vec3} out
*/
export function transformMat4(out, a, m) {
let x = a[0], y = a[1], z = a[2];
let w = m[3] * x + m[7] * y + m[11] * z + m[15];
w = w || 1.0;
out[0] = (m[0] * x + m[4] * y + m[8] * z + m[12]) / w;
out[1] = (m[1] * x + m[5] * y + m[9] * z + m[13]) / w;
out[2] = (m[2] * x + m[6] * y + m[10] * z + m[14]) / w;
return out;
}
/**
* Transforms the vec3 with a mat3.
*
* @param {vec3} out the receiving vector
* @param {vec3} a the vector to transform
* @param {mat3} m the 3x3 matrix to transform with
* @returns {vec3} out
*/
export function transformMat3(out, a, m) {
let x = a[0], y = a[1], z = a[2];
out[0] = x * m[0] + y * m[3] + z * m[6];
out[1] = x * m[1] + y * m[4] + z * m[7];
out[2] = x * m[2] + y * m[5] + z * m[8];
return out;
}
/**
* Transforms the vec3 with a quat
*
* @param {vec3} out the receiving vector
* @param {vec3} a the vector to transform
* @param {quat} q quaternion to transform with
* @returns {vec3} out
*/
export function transformQuat(out, a, q) {
// benchmarks: http://jsperf.com/quaternion-transform-vec3-implementations
let x = a[0], y = a[1], z = a[2];
let qx = q[0], qy = q[1], qz = q[2], qw = q[3];
// calculate quat * vec
let ix = qw * x + qy * z - qz * y;
let iy = qw * y + qz * x - qx * z;
let iz = qw * z + qx * y - qy * x;
let iw = -qx * x - qy * y - qz * z;
// calculate result * inverse quat
out[0] = ix * qw + iw * -qx + iy * -qz - iz * -qy;
out[1] = iy * qw + iw * -qy + iz * -qx - ix * -qz;
out[2] = iz * qw + iw * -qz + ix * -qy - iy * -qx;
return out;
}
/**
* Rotate a 3D vector around the x-axis
* @param {vec3} out The receiving vec3
* @param {vec3} a The vec3 point to rotate
* @param {vec3} b The origin of the rotation
* @param {Number} c The angle of rotation
* @returns {vec3} out
*/
export function rotateX(out, a, b, c){
let p = [], r=[];
//Translate point to the origin
p[0] = a[0] - b[0];
p[1] = a[1] - b[1];
p[2] = a[2] - b[2];
//perform rotation
r[0] = p[0];
r[1] = p[1]*Math.cos(c) - p[2]*Math.sin(c);
r[2] = p[1]*Math.sin(c) + p[2]*Math.cos(c);
//translate to correct position
out[0] = r[0] + b[0];
out[1] = r[1] + b[1];
out[2] = r[2] + b[2];
return out;
}
/**
* Rotate a 3D vector around the y-axis
* @param {vec3} out The receiving vec3
* @param {vec3} a The vec3 point to rotate
* @param {vec3} b The origin of the rotation
* @param {Number} c The angle of rotation
* @returns {vec3} out
*/
export function rotateY(out, a, b, c){
let p = [], r=[];
//Translate point to the origin
p[0] = a[0] - b[0];
p[1] = a[1] - b[1];
p[2] = a[2] - b[2];
//perform rotation
r[0] = p[2]*Math.sin(c) + p[0]*Math.cos(c);
r[1] = p[1];
r[2] = p[2]*Math.cos(c) - p[0]*Math.sin(c);
//translate to correct position
out[0] = r[0] + b[0];
out[1] = r[1] + b[1];
out[2] = r[2] + b[2];
return out;
}
/**
* Rotate a 3D vector around the z-axis
* @param {vec3} out The receiving vec3
* @param {vec3} a The vec3 point to rotate
* @param {vec3} b The origin of the rotation
* @param {Number} c The angle of rotation
* @returns {vec3} out
*/
export function rotateZ(out, a, b, c){
let p = [], r=[];
//Translate point to the origin
p[0] = a[0] - b[0];
p[1] = a[1] - b[1];
p[2] = a[2] - b[2];
//perform rotation
r[0] = p[0]*Math.cos(c) - p[1]*Math.sin(c);
r[1] = p[0]*Math.sin(c) + p[1]*Math.cos(c);
r[2] = p[2];
//translate to correct position
out[0] = r[0] + b[0];
out[1] = r[1] + b[1];
out[2] = r[2] + b[2];
return out;
}
/**
* Get the angle between two 3D vectors
* @param {vec3} a The first operand
* @param {vec3} b The second operand
* @returns {Number} The angle in radians
*/
export function angle(a, b) {
let tempA = fromValues(a[0], a[1], a[2]);
let tempB = fromValues(b[0], b[1], b[2]);
normalize(tempA, tempA);
normalize(tempB, tempB);
let cosine = dot(tempA, tempB);
if(cosine > 1.0) {
return 0;
}
else if(cosine < -1.0) {
return Math.PI;
} else {
return Math.acos(cosine);
}
}
/**
* Returns a string representation of a vector
*
* @param {vec3} a vector to represent as a string
* @returns {String} string representation of the vector
*/
export function str(a) {
return 'vec3(' + a[0] + ', ' + a[1] + ', ' + a[2] + ')';
}
/**
* Returns whether or not the vectors have exactly the same elements in the same position (when compared with ===)
*
* @param {vec3} a The first vector.
* @param {vec3} b The second vector.
* @returns {Boolean} True if the vectors are equal, false otherwise.
*/
export function exactEquals(a, b) {
return a[0] === b[0] && a[1] === b[1] && a[2] === b[2];
}
/**
* Returns whether or not the vectors have approximately the same elements in the same position.
*
* @param {vec3} a The first vector.
* @param {vec3} b The second vector.
* @returns {Boolean} True if the vectors are equal, false otherwise.
*/
export function equals(a, b) {
let a0 = a[0], a1 = a[1], a2 = a[2];
let b0 = b[0], b1 = b[1], b2 = b[2];
return (Math.abs(a0 - b0) <= glMatrix.EPSILON*Math.max(1.0, Math.abs(a0), Math.abs(b0)) &&
Math.abs(a1 - b1) <= glMatrix.EPSILON*Math.max(1.0, Math.abs(a1), Math.abs(b1)) &&
Math.abs(a2 - b2) <= glMatrix.EPSILON*Math.max(1.0, Math.abs(a2), Math.abs(b2)));
}
/**
* Alias for {@link vec3.subtract}
* @function
*/
export const sub = subtract;
/**
* Alias for {@link vec3.multiply}
* @function
*/
export const mul = multiply;
/**
* Alias for {@link vec3.divide}
* @function
*/
export const div = divide;
/**
* Alias for {@link vec3.distance}
* @function
*/
export const dist = distance;
/**
* Alias for {@link vec3.squaredDistance}
* @function
*/
export const sqrDist = squaredDistance;
/**
* Alias for {@link vec3.length}
* @function
*/
export const len = length;
/**
* Alias for {@link vec3.squaredLength}
* @function
*/
export const sqrLen = squaredLength;
/**
* Perform some operation over an array of vec3s.
*
* @param {Array} a the array of vectors to iterate over
* @param {Number} stride Number of elements between the start of each vec3. If 0 assumes tightly packed
* @param {Number} offset Number of elements to skip at the beginning of the array
* @param {Number} count Number of vec3s to iterate over. If 0 iterates over entire array
* @param {Function} fn Function to call for each vector in the array
* @param {Object} [arg] additional argument to pass to fn
* @returns {Array} a
* @function
*/
export const forEach = (function() {
let vec = create();
return function(a, stride, offset, count, fn, arg) {
let i, l;
if(!stride) {
stride = 3;
}
if(!offset) {
offset = 0;
}
if(count) {
l = Math.min((count * stride) + offset, a.length);
} else {
l = a.length;
}
for(i = offset; i < l; i += stride) {
vec[0] = a[i]; vec[1] = a[i+1]; vec[2] = a[i+2];
fn(vec, vec, arg);
a[i] = vec[0]; a[i+1] = vec[1]; a[i+2] = vec[2];
}
return a;
};
})();

View File

@@ -1,606 +0,0 @@
/* Copyright (c) 2015, Brandon Jones, Colin MacKenzie IV.
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE. */
import * as glMatrix from "./common";
/**
* 4 Dimensional Vector
* @module vec4
*/
/**
* Creates a new, empty vec4
*
* @returns {vec4} a new 4D vector
*/
export function create() {
let out = new glMatrix.ARRAY_TYPE(4);
out[0] = 0;
out[1] = 0;
out[2] = 0;
out[3] = 0;
return out;
}
/**
* Creates a new vec4 initialized with values from an existing vector
*
* @param {vec4} a vector to clone
* @returns {vec4} a new 4D vector
*/
export function clone(a) {
let out = new glMatrix.ARRAY_TYPE(4);
out[0] = a[0];
out[1] = a[1];
out[2] = a[2];
out[3] = a[3];
return out;
}
/**
* Creates a new vec4 initialized with the given values
*
* @param {Number} x X component
* @param {Number} y Y component
* @param {Number} z Z component
* @param {Number} w W component
* @returns {vec4} a new 4D vector
*/
export function fromValues(x, y, z, w) {
let out = new glMatrix.ARRAY_TYPE(4);
out[0] = x;
out[1] = y;
out[2] = z;
out[3] = w;
return out;
}
/**
* Copy the values from one vec4 to another
*
* @param {vec4} out the receiving vector
* @param {vec4} a the source vector
* @returns {vec4} out
*/
export function copy(out, a) {
out[0] = a[0];
out[1] = a[1];
out[2] = a[2];
out[3] = a[3];
return out;
}
/**
* Set the components of a vec4 to the given values
*
* @param {vec4} out the receiving vector
* @param {Number} x X component
* @param {Number} y Y component
* @param {Number} z Z component
* @param {Number} w W component
* @returns {vec4} out
*/
export function set(out, x, y, z, w) {
out[0] = x;
out[1] = y;
out[2] = z;
out[3] = w;
return out;
}
/**
* Adds two vec4's
*
* @param {vec4} out the receiving vector
* @param {vec4} a the first operand
* @param {vec4} b the second operand
* @returns {vec4} out
*/
export function add(out, a, b) {
out[0] = a[0] + b[0];
out[1] = a[1] + b[1];
out[2] = a[2] + b[2];
out[3] = a[3] + b[3];
return out;
}
/**
* Subtracts vector b from vector a
*
* @param {vec4} out the receiving vector
* @param {vec4} a the first operand
* @param {vec4} b the second operand
* @returns {vec4} out
*/
export function subtract(out, a, b) {
out[0] = a[0] - b[0];
out[1] = a[1] - b[1];
out[2] = a[2] - b[2];
out[3] = a[3] - b[3];
return out;
}
/**
* Multiplies two vec4's
*
* @param {vec4} out the receiving vector
* @param {vec4} a the first operand
* @param {vec4} b the second operand
* @returns {vec4} out
*/
export function multiply(out, a, b) {
out[0] = a[0] * b[0];
out[1] = a[1] * b[1];
out[2] = a[2] * b[2];
out[3] = a[3] * b[3];
return out;
}
/**
* Divides two vec4's
*
* @param {vec4} out the receiving vector
* @param {vec4} a the first operand
* @param {vec4} b the second operand
* @returns {vec4} out
*/
export function divide(out, a, b) {
out[0] = a[0] / b[0];
out[1] = a[1] / b[1];
out[2] = a[2] / b[2];
out[3] = a[3] / b[3];
return out;
}
/**
* Math.ceil the components of a vec4
*
* @param {vec4} out the receiving vector
* @param {vec4} a vector to ceil
* @returns {vec4} out
*/
export function ceil(out, a) {
out[0] = Math.ceil(a[0]);
out[1] = Math.ceil(a[1]);
out[2] = Math.ceil(a[2]);
out[3] = Math.ceil(a[3]);
return out;
}
/**
* Math.floor the components of a vec4
*
* @param {vec4} out the receiving vector
* @param {vec4} a vector to floor
* @returns {vec4} out
*/
export function floor(out, a) {
out[0] = Math.floor(a[0]);
out[1] = Math.floor(a[1]);
out[2] = Math.floor(a[2]);
out[3] = Math.floor(a[3]);
return out;
}
/**
* Returns the minimum of two vec4's
*
* @param {vec4} out the receiving vector
* @param {vec4} a the first operand
* @param {vec4} b the second operand
* @returns {vec4} out
*/
export function min(out, a, b) {
out[0] = Math.min(a[0], b[0]);
out[1] = Math.min(a[1], b[1]);
out[2] = Math.min(a[2], b[2]);
out[3] = Math.min(a[3], b[3]);
return out;
}
/**
* Returns the maximum of two vec4's
*
* @param {vec4} out the receiving vector
* @param {vec4} a the first operand
* @param {vec4} b the second operand
* @returns {vec4} out
*/
export function max(out, a, b) {
out[0] = Math.max(a[0], b[0]);
out[1] = Math.max(a[1], b[1]);
out[2] = Math.max(a[2], b[2]);
out[3] = Math.max(a[3], b[3]);
return out;
}
/**
* Math.round the components of a vec4
*
* @param {vec4} out the receiving vector
* @param {vec4} a vector to round
* @returns {vec4} out
*/
export function round(out, a) {
out[0] = Math.round(a[0]);
out[1] = Math.round(a[1]);
out[2] = Math.round(a[2]);
out[3] = Math.round(a[3]);
return out;
}
/**
* Scales a vec4 by a scalar number
*
* @param {vec4} out the receiving vector
* @param {vec4} a the vector to scale
* @param {Number} b amount to scale the vector by
* @returns {vec4} out
*/
export function scale(out, a, b) {
out[0] = a[0] * b;
out[1] = a[1] * b;
out[2] = a[2] * b;
out[3] = a[3] * b;
return out;
}
/**
* Adds two vec4's after scaling the second operand by a scalar value
*
* @param {vec4} out the receiving vector
* @param {vec4} a the first operand
* @param {vec4} b the second operand
* @param {Number} scale the amount to scale b by before adding
* @returns {vec4} out
*/
export function scaleAndAdd(out, a, b, scale) {
out[0] = a[0] + (b[0] * scale);
out[1] = a[1] + (b[1] * scale);
out[2] = a[2] + (b[2] * scale);
out[3] = a[3] + (b[3] * scale);
return out;
}
/**
* Calculates the euclidian distance between two vec4's
*
* @param {vec4} a the first operand
* @param {vec4} b the second operand
* @returns {Number} distance between a and b
*/
export function distance(a, b) {
let x = b[0] - a[0];
let y = b[1] - a[1];
let z = b[2] - a[2];
let w = b[3] - a[3];
return Math.sqrt(x*x + y*y + z*z + w*w);
}
/**
* Calculates the squared euclidian distance between two vec4's
*
* @param {vec4} a the first operand
* @param {vec4} b the second operand
* @returns {Number} squared distance between a and b
*/
export function squaredDistance(a, b) {
let x = b[0] - a[0];
let y = b[1] - a[1];
let z = b[2] - a[2];
let w = b[3] - a[3];
return x*x + y*y + z*z + w*w;
}
/**
* Calculates the length of a vec4
*
* @param {vec4} a vector to calculate length of
* @returns {Number} length of a
*/
export function length(a) {
let x = a[0];
let y = a[1];
let z = a[2];
let w = a[3];
return Math.sqrt(x*x + y*y + z*z + w*w);
}
/**
* Calculates the squared length of a vec4
*
* @param {vec4} a vector to calculate squared length of
* @returns {Number} squared length of a
*/
export function squaredLength(a) {
let x = a[0];
let y = a[1];
let z = a[2];
let w = a[3];
return x*x + y*y + z*z + w*w;
}
/**
* Negates the components of a vec4
*
* @param {vec4} out the receiving vector
* @param {vec4} a vector to negate
* @returns {vec4} out
*/
export function negate(out, a) {
out[0] = -a[0];
out[1] = -a[1];
out[2] = -a[2];
out[3] = -a[3];
return out;
}
/**
* Returns the inverse of the components of a vec4
*
* @param {vec4} out the receiving vector
* @param {vec4} a vector to invert
* @returns {vec4} out
*/
export function inverse(out, a) {
out[0] = 1.0 / a[0];
out[1] = 1.0 / a[1];
out[2] = 1.0 / a[2];
out[3] = 1.0 / a[3];
return out;
}
/**
* Normalize a vec4
*
* @param {vec4} out the receiving vector
* @param {vec4} a vector to normalize
* @returns {vec4} out
*/
export function normalize(out, a) {
let x = a[0];
let y = a[1];
let z = a[2];
let w = a[3];
let len = x*x + y*y + z*z + w*w;
if (len > 0) {
len = 1 / Math.sqrt(len);
out[0] = x * len;
out[1] = y * len;
out[2] = z * len;
out[3] = w * len;
}
return out;
}
/**
* Calculates the dot product of two vec4's
*
* @param {vec4} a the first operand
* @param {vec4} b the second operand
* @returns {Number} dot product of a and b
*/
export function dot(a, b) {
return a[0] * b[0] + a[1] * b[1] + a[2] * b[2] + a[3] * b[3];
}
/**
* Performs a linear interpolation between two vec4's
*
* @param {vec4} out the receiving vector
* @param {vec4} a the first operand
* @param {vec4} b the second operand
* @param {Number} t interpolation amount between the two inputs
* @returns {vec4} out
*/
export function lerp(out, a, b, t) {
let ax = a[0];
let ay = a[1];
let az = a[2];
let aw = a[3];
out[0] = ax + t * (b[0] - ax);
out[1] = ay + t * (b[1] - ay);
out[2] = az + t * (b[2] - az);
out[3] = aw + t * (b[3] - aw);
return out;
}
/**
* Generates a random vector with the given scale
*
* @param {vec4} out the receiving vector
* @param {Number} [scale] Length of the resulting vector. If ommitted, a unit vector will be returned
* @returns {vec4} out
*/
export function random(out, vectorScale) {
vectorScale = vectorScale || 1.0;
//TODO: This is a pretty awful way of doing this. Find something better.
out[0] = glMatrix.RANDOM();
out[1] = glMatrix.RANDOM();
out[2] = glMatrix.RANDOM();
out[3] = glMatrix.RANDOM();
normalize(out, out);
scale(out, out, vectorScale);
return out;
}
/**
* Transforms the vec4 with a mat4.
*
* @param {vec4} out the receiving vector
* @param {vec4} a the vector to transform
* @param {mat4} m matrix to transform with
* @returns {vec4} out
*/
export function transformMat4(out, a, m) {
let x = a[0], y = a[1], z = a[2], w = a[3];
out[0] = m[0] * x + m[4] * y + m[8] * z + m[12] * w;
out[1] = m[1] * x + m[5] * y + m[9] * z + m[13] * w;
out[2] = m[2] * x + m[6] * y + m[10] * z + m[14] * w;
out[3] = m[3] * x + m[7] * y + m[11] * z + m[15] * w;
return out;
}
/**
* Transforms the vec4 with a quat
*
* @param {vec4} out the receiving vector
* @param {vec4} a the vector to transform
* @param {quat} q quaternion to transform with
* @returns {vec4} out
*/
export function transformQuat(out, a, q) {
let x = a[0], y = a[1], z = a[2];
let qx = q[0], qy = q[1], qz = q[2], qw = q[3];
// calculate quat * vec
let ix = qw * x + qy * z - qz * y;
let iy = qw * y + qz * x - qx * z;
let iz = qw * z + qx * y - qy * x;
let iw = -qx * x - qy * y - qz * z;
// calculate result * inverse quat
out[0] = ix * qw + iw * -qx + iy * -qz - iz * -qy;
out[1] = iy * qw + iw * -qy + iz * -qx - ix * -qz;
out[2] = iz * qw + iw * -qz + ix * -qy - iy * -qx;
out[3] = a[3];
return out;
}
/**
* Returns a string representation of a vector
*
* @param {vec4} a vector to represent as a string
* @returns {String} string representation of the vector
*/
export function str(a) {
return 'vec4(' + a[0] + ', ' + a[1] + ', ' + a[2] + ', ' + a[3] + ')';
}
/**
* Returns whether or not the vectors have exactly the same elements in the same position (when compared with ===)
*
* @param {vec4} a The first vector.
* @param {vec4} b The second vector.
* @returns {Boolean} True if the vectors are equal, false otherwise.
*/
export function exactEquals(a, b) {
return a[0] === b[0] && a[1] === b[1] && a[2] === b[2] && a[3] === b[3];
}
/**
* Returns whether or not the vectors have approximately the same elements in the same position.
*
* @param {vec4} a The first vector.
* @param {vec4} b The second vector.
* @returns {Boolean} True if the vectors are equal, false otherwise.
*/
export function equals(a, b) {
let a0 = a[0], a1 = a[1], a2 = a[2], a3 = a[3];
let b0 = b[0], b1 = b[1], b2 = b[2], b3 = b[3];
return (Math.abs(a0 - b0) <= glMatrix.EPSILON*Math.max(1.0, Math.abs(a0), Math.abs(b0)) &&
Math.abs(a1 - b1) <= glMatrix.EPSILON*Math.max(1.0, Math.abs(a1), Math.abs(b1)) &&
Math.abs(a2 - b2) <= glMatrix.EPSILON*Math.max(1.0, Math.abs(a2), Math.abs(b2)) &&
Math.abs(a3 - b3) <= glMatrix.EPSILON*Math.max(1.0, Math.abs(a3), Math.abs(b3)));
}
/**
* Alias for {@link vec4.subtract}
* @function
*/
export const sub = subtract;
/**
* Alias for {@link vec4.multiply}
* @function
*/
export const mul = multiply;
/**
* Alias for {@link vec4.divide}
* @function
*/
export const div = divide;
/**
* Alias for {@link vec4.distance}
* @function
*/
export const dist = distance;
/**
* Alias for {@link vec4.squaredDistance}
* @function
*/
export const sqrDist = squaredDistance;
/**
* Alias for {@link vec4.length}
* @function
*/
export const len = length;
/**
* Alias for {@link vec4.squaredLength}
* @function
*/
export const sqrLen = squaredLength;
/**
* Perform some operation over an array of vec4s.
*
* @param {Array} a the array of vectors to iterate over
* @param {Number} stride Number of elements between the start of each vec4. If 0 assumes tightly packed
* @param {Number} offset Number of elements to skip at the beginning of the array
* @param {Number} count Number of vec4s to iterate over. If 0 iterates over entire array
* @param {Function} fn Function to call for each vector in the array
* @param {Object} [arg] additional argument to pass to fn
* @returns {Array} a
* @function
*/
export const forEach = (function() {
let vec = create();
return function(a, stride, offset, count, fn, arg) {
let i, l;
if(!stride) {
stride = 4;
}
if(!offset) {
offset = 0;
}
if(count) {
l = Math.min((count * stride) + offset, a.length);
} else {
l = a.length;
}
for(i = offset; i < l; i += stride) {
vec[0] = a[i]; vec[1] = a[i+1]; vec[2] = a[i+2]; vec[3] = a[i+3];
fn(vec, vec, arg);
a[i] = vec[0]; a[i+1] = vec[1]; a[i+2] = vec[2]; a[i+3] = vec[3];
}
return a;
};
})();

View File

@@ -1,23 +0,0 @@
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 Program} from './Program';
export {default as Material} from './Material';
export {default as Texture} from './Texture';
export {default as Container} from './Container';
export {default as Mesh} from './Mesh';
export {default as Renderer} from './Renderer';
export {default as Camera} from './Camera';
export {default as Object3d} from './Object3d';
export {default as GeometryBuffer} from './GeometryBuffer';
export {default as PlaneGeometryBuffer} from './PlaneGeometryBuffer';
export {default as SphereGeometryBuffer} from './SphereGeometryBuffer';

View File

@@ -1,8 +0,0 @@
precision highp float;
uniform float alpha;
varying vec2 vUv;
void main(void) {
gl_FragColor = vec4( vec3(1., 1., 1.), alpha);
}

View File

@@ -1,14 +0,0 @@
precision highp float;
attribute vec2 uv;
attribute vec3 position;
uniform mat4 uMVMatrix;
uniform mat4 uPMatrix;
varying vec2 vUv;
void main(void) {
vUv = uv;
gl_Position = uPMatrix * uMVMatrix * vec4(position, 1.0);
}

View File

@@ -1,33 +0,0 @@
precision highp float;
uniform float alpha;
varying vec3 vColor;
varying vec2 vUv;
uniform vec2 offset;
#ifdef USE_MAP
uniform sampler2D map;
uniform vec2 mapOffset;
#endif
#ifdef USE_ALPHA_MAP
uniform sampler2D alphaMap;
uniform vec2 alphaMapOffset;
#endif
uniform vec3 color;
void main(void) {
vec4 color = vec4(color, alpha);
#ifdef USE_MAP
color = texture2D(map, vUv + offset);
color.a *= alpha;
#endif
gl_FragColor = color;
}

View File

@@ -1,20 +0,0 @@
const UNIFORM_TYPES = {}
UNIFORM_TYPES[ 5126 /*FLOAT */ ] = '1f';
UNIFORM_TYPES[ 35664 /*FLOAT_VEC2 */ ] = '2f';
UNIFORM_TYPES[ 35665 /*FLOAT_VEC3 */ ] = '3f';
UNIFORM_TYPES[ 35666 /*FLOAT_VEC4 */ ] = '4f';
UNIFORM_TYPES[ 35670 /*BOOL */ ] =
UNIFORM_TYPES[ 5124 /*INT */ ] =
UNIFORM_TYPES[ 35678 /*SAMPLER_2D */ ] =
UNIFORM_TYPES[ 35680 /*SAMPLER_CUBE*/ ] = '1i';
UNIFORM_TYPES[ 35671 /*BOOL_VEC2 */ ] =
UNIFORM_TYPES[ 35667 /*INT_VEC2 */ ] = '2i';
UNIFORM_TYPES[ 35672 /*BOOL_VEC3 */ ] =
UNIFORM_TYPES[ 35668 /*INT_VEC3 */ ] = '3i';
UNIFORM_TYPES[ 35673 /*BOOL_VEC4 */ ] =
UNIFORM_TYPES[ 35669 /*INT_VEC4 */ ] = '4i';
UNIFORM_TYPES[ 35674 /*FLOAT_MAT2 */ ] = 'Matrix2f';
UNIFORM_TYPES[ 35675 /*FLOAT_MAT3 */ ] = 'Matrix3f';
UNIFORM_TYPES[ 35676 /*FLOAT_MAT4 */ ] = 'Matrix4f';
export default UNIFORM_TYPES;

View File

@@ -1,12 +0,0 @@
/*
* compute filtering enum, return one of the following :
* NEAREST
* LINEAR
* NEAREST_MIPMAP_NEAREST
* LINEAR_MIPMAP_NEAREST
* NEAREST_MIPMAP_LINEAR
* LINEAR_MIPMAP_LINEAR
*/
export default function getFilter( smooth, mipmap, miplinear ){
return 0x2600 | (+smooth) | (+mipmap<<8) | ( +( mipmap && miplinear )<<1 );
}

View File

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

View File

@@ -1,20 +0,0 @@
// http://www.broofa.com/Tools/Math.uuid.htm
var chars = '0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz'.split( '' );
var uuid = new Array( 36 );
var rnd = 0, r;
export default function generateUUID() {
for ( var i = 0; i < 36; i ++ ) {
if ( i === 8 || i === 13 || i === 18 || i === 23 ) {
uuid[ i ] = '-';
} else if ( i === 14 ) {
uuid[ i ] = '4';
} else {
if ( rnd <= 0x02 ) rnd = 0x2000000 + ( Math.random() * 0x1000000 ) | 0;
r = rnd & 0xf;
rnd = rnd >> 4;
uuid[ i ] = chars[ ( i === 19 ) ? ( r & 0x3 ) | 0x8 : r ];
}
}
return uuid.join( '' );
}

View File

@@ -1,3 +0,0 @@
export default function warn(msg, ctx){
console.log("%c" + "[warn]: " + msg, "color:#ff0084", ctx );
}

View File

@@ -1,53 +0,0 @@
#define PI 3.34159265359
#define RECIPROCAL_PI 0.31830988618
#define saturate(a) clamp(a, 0.0, 1.0)
precision highp float;
varying vec3 vNormal;
varying vec2 vUv;
varying vec3 vPos;
uniform sampler2D tInput;
uniform vec3 uCameraPosition;
vec3 F_Schlick_Frostbite (in vec3 f0, in float f90, in float u) {
return f0 + (f90 - f0) * pow (1. - u, 5.);
}
void main (void) {
vec3 N = vNormal;
vec3 outColor = vec3(0.);
vec3 diffuseColor = texture2D(tInput, vUv).rgb; //pow(texture2D(tInput, vUv).rgb, vec3(2.2));
vec3 V = normalize(uCameraPosition - vPos);
vec3 L = normalize(vec3(20., 20., 20.));
vec3 Ldir = normalize(L - vPos);
vec3 radiance = vec3(0.);
float NdotL = max(0., dot(N, L));
vec3 lColor = vec3(1.);
float attenuation = 1.; // calcLightAttenuation(length(L - worldPos), directLight.distance, directLight.decay);
float roughness = clamp(1., 0.04, 1.0);
vec3 H = normalize(L);
float LdotH = saturate(dot(L, H));
float NdotH = saturate(dot(N, H));
float energyBias = mix(0., 0.5, roughness);
float energyFactor = mix(1.0, 1.0 / 1.51, roughness);
float f90 = energyBias + 2.0 * LdotH * LdotH * roughness;
vec3 f0 = vec3(1.0, 1.0, 1.0);
float lightScatter = F_Schlick_Frostbite (f0, f90, NdotL).r;
vec3 irradiance = NdotL * lColor;
outColor = diffuseColor * irradiance * lightScatter * energyFactor * attenuation;
vec3 ambient = vec3(192./255., 181./255., 215./255.);
// outColor.r = max(ambient.r, outColor.r);
// outColor.g = max(ambient.g, outColor.g);
// outColor.b = max(ambient.b, outColor.b);
outColor = diffuseColor * vec3(NdotL) + diffuseColor * ambient * (1. - NdotL);
gl_FragColor = vec4(outColor, 1.);
}

View File

@@ -1,24 +0,0 @@
precision highp float;
attribute vec3 normal;
attribute vec3 position;
attribute vec2 uv;
uniform mat4 uMVMatrix;
uniform mat4 uMMatrix;
uniform mat4 uPMatrix;
uniform mat4 uNormalMatrix;
uniform float uCameraOffsetY;
varying vec2 vUv;
varying vec3 vNormal;
varying vec3 vPos;
void main(void) {
vUv = uv;
vNormal = (uNormalMatrix * vec4(normal, 1.)).rgb;
vPos = (uMMatrix * vec4(position, 1.)).rgb;
gl_Position = uPMatrix * uMVMatrix * vec4(position, 1.0);
gl_Position[1] += uCameraOffsetY * gl_Position.w;
}

View File

@@ -1,421 +0,0 @@
import { Renderer } from './beam'
import { Camera } from './beam'
import { vec2, vec3, mat4 } from './beam'
import { Container, Mesh, Material, Texture, SphereGeometryBuffer, PlaneGeometryBuffer } from './beam'
// GLSL shaders as strings
import GlobeVS from './globe-vs.glsl?raw'
import GlobeFS from './globe-fs.glsl?raw'
const FOV = 1 // Camera Field of view; we use 1 to prevent strong perspective effect on the globe
/** get 3D position on a sphere from longitute lattitude */
const lonLatToVector3 = (lng, lat) => {
const phi = (90 - lat) * (Math.PI / 180)
const theta = (lng + 180) * (Math.PI / 180)
const x = -(Math.sin(phi) * Math.cos(theta))
const z = Math.sin(phi) * Math.sin(theta)
const y = Math.cos(phi)
return [x,y,z]
}
// Convert degrees to radians
const degToRad = deg => deg * Math.PI / 180
class WebglGlobe {
// Constructor
constructor (options) {
this.$el = options.el // The DOM reference node
this.options = options
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 = 1 // this.options.cameraDistance || 1 // A multiplier to move camera backward or forward
this.options.opacity = this.options.opacity || 1
this.locations = options.markers // List of locations with their options
this._canUpdate = false
this.hasUpdateCameraPos = false
this.referenceHeight = 1 // Used to set camera distance from globe where referenceHeight == window height
this.currMarkerScrollOffset = 0
this.markersScrollOffset = 0
this.globeScrollOffset = 0
this.globeAutoRotation = degToRad(this.options.rotationStart * -1) || 0
this._isHoverMarker = false
let gl
const canvas = document.createElement('canvas')
try {
gl = canvas.getContext('webgl')
} catch (x) {
try {
gl = canvas.getContext('experimental-webgl')
} catch (x) {
gl = null
}
}
this.supportWebgl = gl !== null
if (this.supportWebgl) {
this.buildWebglScene()
this.resize()
}
}
/**
* Build scene
*/
buildWebglScene () {
// Renderer
this.renderer = new Renderer({
// To allow transparent background on webgl canvas
alpha: true,
// Enable antialiasing only if screen is small with no retina (for performances reasons)
antialias: window.innerWidth < 768 || window.devicePixelRatio == 1 ? true : false,
})
const elParent = document.body
// 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.classList.add('globe-canvas')
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
elParent.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('globe-markers')
this.$markerWrapper.style.position = 'fixed'
this.$markerWrapper.style.top = 0
this.$markerWrapper.style.left = 0
this.$markerWrapper.style.pointerEvents = 'none'
elParent.appendChild(this.$markerWrapper)
// Load worldmap texture
this.texture = Texture.fromUrl(this.renderer.gl, this.options.texture, {
loaded: () => {
//TODO: use only one RAF if possible
requestAnimationFrame(() => {
requestAnimationFrame(() => {
this.imageLoaded = true
})
})
}
})
this.scene = new Container()
/**
* Setup camera
*/
this.camera = new Camera({
fov: 1,
near: 0.1,
far: 1000,
type: 'perspective',
orbitControl: true,
firstPerson: false,
lookAt: [0,0,0],
position: [0,0,0],
pointerParent: this.$el
})
this.camera.lookAt = vec3.create()
/**
* used to compute screen position of markers,
* to move the corresponding DOM nodes
*/
this.viewProjectionMatrix = mat4.create()
this.cameraPosition = vec3.create()
this.globeMesh = new Mesh()
this.globeMesh.material = new Material(this.renderer.gl, {
uniforms: {
tInput: this.texture,
uCameraOffsetY: 0,
},
vertexShader: GlobeVS,
fragmentShader: GlobeFS,
})
this.globeMesh.geometry = new SphereGeometryBuffer(this.renderer.gl, {
radius: this.referenceHeight / 2,
widthSegments: 100, heightSegments: 100
})
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)
/**
* Add drag and touch event listeners
*/
const addDragingClass = () => this.$el.classList.add('is-dragging')
const removeDragingClass = () => this.$el.classList.remove('is-dragging')
this.$el.addEventListener('dragstart', addDragingClass)
this.$el.addEventListener('dragend', removeDragingClass)
/**
* Create DOM nodes for markers and 3D positions
*/
this.markers = []
let markers = this.locations
// Instance all markers
for (let i = 0; i < markers.length; i++) {
// Position marker
let p = lonLatToVector3(markers[i].lng, markers[i].lat)
// Scale marker position to fit globe size
p[0] *= this.referenceHeight / 2
p[1] *= this.referenceHeight / 2
p[2] *= this.referenceHeight / 2
// Wrap marker in link
let el = document.createElement('a')
el.style.pointerEvents = 'auto'
el.setAttribute('href', `/${markers[i].countrySlug}/${markers[i].slug}`)
el.setAttribute('sveltekit-noscroll', '')
if (markers[i].className) el.classList.add(markers[i].className)
// Add label
let span = document.createElement('span')
span.classList.add('marker__label')
el.appendChild(span)
// Add city label
let spanCity = document.createElement('span')
spanCity.classList.add('marker__city')
spanCity.innerHTML = markers[i].name
span.appendChild(spanCity)
// Add country label
let spanCountry = document.createElement('span')
spanCountry.classList.add('marker__country')
spanCountry.innerHTML = markers[i].countryName
span.appendChild(spanCountry)
// Add class
el.classList.add('marker')
// Add a class if opacity is below 1
if (this.options.opacity < 1) {
el.classList.add('is-light')
}
// Callback on click
el.addEventListener('click', () => {
this.options.onLinkClicked && this.options.onLinkClicked()
})
// Add class on hover
el.addEventListener('mouseenter', () => {
el.classList.add('hover')
// Stop globe rotation
this._isHoverMarker = true
// Clear timeout to be sure
clearTimeout(this.hoverTimeout)
})
el.addEventListener('mouseleave', () => {
// Restart rotation after a little delay
this.hoverTimeout = setTimeout(() => this._isHoverMarker = false, 400)
})
el.addEventListener('animationend', () => {
el.classList.remove('hover')
})
// Append marker to HTML
this.$markerWrapper.appendChild(el)
this.markers.push({
el: el,
position: p,
screenPosition: [0,0]
})
}
}
/**
* Resize method
*/
resize () {
if (!this.supportWebgl) {
return
}
this.width = window ? window.innerWidth : 0
this.height = window ? window.innerHeight : 0
//fit globe to container height
this.options.cameraDistance = this.height / this.$el.clientHeight;
// 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()
// Distance to put the camera when rotating around the globe
this.camera._cameraDistance = (this.referenceHeight * this.options.cameraDistance) / 2 / Math.tan(Math.PI * FOV / 360)
this.camera.update(true)
/**
* When markers are behind the globe, clamp their position
* to this size to make them move along the circle edge
*/
this.circleScreenSize = (this.height / 2) * (1 / this.options.cameraDistance)
}
/**
* As the camera rotates arount the globe, we cant simply move the Y position of the camera or the globe
* 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
*/
updateCameraPos (y, scrollDiff) {
this.globeScrollOffset = y
this.markersScrollOffset = scrollDiff
// Avoid jump due to smoothing when setting it for first time as the inital values are 0
if (!this.hasUpdateCameraPos) {
this.hasUpdateCameraPos = true
if (this.globeMesh.material.uniforms.uCameraOffsetY) {
this.globeMesh.material.uniforms.uCameraOffsetY.value = this.globeScrollOffset
}
this.currMarkerScrollOffset = this.markersScrollOffset
}
}
/**
* Destroy the globe
*/
destroy () {
this.disable() // Stop render loop
document.body.removeChild(this.$markerWrapper)
document.body.removeChild(this.renderer.canvas)
this.camera.delete() // To remove event listeners
}
/**
* Flag to stop rendering the webgl if the globe isnt visible
* This helps saving perfs and battery
*/
enable () {
this.renderer.canvas.style.opacity = this.options.opacity
this.$markerWrapper.style.opacity = 1
this._canUpdate = true
}
disable () {
this.renderer.canvas.style.opacity = 0
this.$markerWrapper.style.opacity = 0
this._canUpdate = false
}
/**
* Update
*/
update () {
if (!this.supportWebgl || !this._canUpdate || !this.imageLoaded || !this.hasUpdateCameraPos) {
return
}
if (this.globeMesh.material.uniforms.uCameraOffsetY) {
this.globeMesh.material.uniforms.uCameraOffsetY.value += (this.globeScrollOffset - this.globeMesh.material.uniforms.uCameraOffsetY.value) * this.options.scrollSmoothing
}
this.currMarkerScrollOffset += (this.markersScrollOffset - this.currMarkerScrollOffset) * this.options.scrollSmoothing
// Compute the camera view-projection matrix to use it on the markers
this.camera.update()
vec3.set(this.cameraPosition, this.camera.worldMatrix[12], this.camera.worldMatrix[13], this.camera.worldMatrix[14])
mat4.copy(this.viewProjectionMatrix, this.camera.projectionMatrix)
mat4.multiply(this.viewProjectionMatrix, this.viewProjectionMatrix, this.camera.inverseWorldMatrix)
// Auto rotate the globe if not hover a marker
if (!this._isHoverMarker) {
this.globeAutoRotation += this.options.autoRotationSpeed
this.globeMesh.rotation[1] = this.globeAutoRotation
}
this.globeMesh.updateMatrix()
this.globeMesh.updateWorldMatrix()
let screenPos = vec3.create()
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.transformMat4(screenPos, screenPos, this.globeMesh.worldMatrix)
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 y = (1. - (screenPos[1] + 1) / 2) * this.height
// Compute marker Normal
let N = vec3.create()
vec3.set(N, marker.position[0], marker.position[1], marker.position[2])
vec3.transformMat4(N, N, this.globeMesh.worldMatrix)
vec3.normalize(N, N)
// Compute view vector (camera direction)
let V = vec3.create()
vec3.set(V, marker.position[0], marker.position[1], marker.position[2])
vec3.subtract(V, V, this.cameraPosition)
vec3.normalize(V, V)
// Marker is behind the globe: clamp it to the globe edge
if (vec3.dot(V, N) * -1 < 0) {
let dir = vec2.create()
vec2.set(dir, x, y)
let center = vec2.create()
vec2.set(center, this.width/2, this.height/2)
let dir2d = vec2.clone(dir) // vec2.clone(dir, dir)
vec2.subtract(dir2d, dir2d, center)
vec2.normalize(dir2d, dir2d)
vec2.scale(dir2d, dir2d, this.circleScreenSize)
vec2.add(dir2d, dir2d, center)
dir2d[1] += this.currMarkerScrollOffset
marker.el.style.transform = `translate(${dir2d[0]}px, ${dir2d[1]}px) translateZ(0)`
marker.el.classList.remove('is-active')
}
// Marker is in front of the globe; update 2D position
else {
y += this.currMarkerScrollOffset
marker.el.style.transform = `translate(${x}px, ${y}px) translateZ(0)`
marker.el.classList.add('is-active')
}
})
// 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.render(this.scene, this.camera)
}
}
// window.WebglGlobe = WebglGlobe
export default WebglGlobe

View File

@@ -3,8 +3,8 @@ import { Renderer, Camera, Vec3, Orbit, Sphere, Transform, Program, Mesh, Textur
import SunCalc from 'suncalc' import SunCalc from 'suncalc'
import { map } from '$utils/functions/index' import { map } from '$utils/functions/index'
// Shaders // Shaders
import VERTEX_SHADER from '$modules/globe2/vertex.glsl?raw' import VERTEX_SHADER from '$modules/globe/vertex.glsl?raw'
import FRAGMENT_SHADER from '$modules/globe2/frag.glsl?raw' import FRAGMENT_SHADER from '$modules/globe/frag.glsl?raw'
export class Globe { export class Globe {

View File

@@ -10,7 +10,7 @@
import PageTransition from '$components/PageTransition.svelte' import PageTransition from '$components/PageTransition.svelte'
import BoxCTA from '$components/atoms/BoxCTA.svelte' import BoxCTA from '$components/atoms/BoxCTA.svelte'
import Heading from '$components/molecules/Heading.svelte' import Heading from '$components/molecules/Heading.svelte'
import InteractiveGlobe2 from '$components/organisms/InteractiveGlobe2.svelte' import InteractiveGlobe from '$components/organisms/InteractiveGlobe.svelte'
import ListCTAs from '$components/organisms/ListCTAs.svelte' import ListCTAs from '$components/organisms/ListCTAs.svelte'
import Locations from '$components/organisms/Locations.svelte' import Locations from '$components/organisms/Locations.svelte'
import ShopModule from '$components/organisms/ShopModule.svelte' import ShopModule from '$components/organisms/ShopModule.svelte'
@@ -68,7 +68,7 @@
</ListCTAs> </ListCTAs>
</div> </div>
<InteractiveGlobe2 /> <InteractiveGlobe />
<Locations {locations} /> <Locations {locations} />
<div class="grid-modules"> <div class="grid-modules">

View File

@@ -21,7 +21,7 @@
import ScrollingTitle from '$components/atoms/ScrollingTitle.svelte' import ScrollingTitle from '$components/atoms/ScrollingTitle.svelte'
import BoxCTA from '$components/atoms/BoxCTA.svelte' import BoxCTA from '$components/atoms/BoxCTA.svelte'
import DiscoverText from '$components/atoms/DiscoverText.svelte' import DiscoverText from '$components/atoms/DiscoverText.svelte'
import InteractiveGlobe2 from '$components/organisms/InteractiveGlobe2.svelte' import InteractiveGlobe from '$components/organisms/InteractiveGlobe.svelte'
import Collage from '$components/organisms/Collage.svelte' import Collage from '$components/organisms/Collage.svelte'
import Locations from '$components/organisms/Locations.svelte' import Locations from '$components/organisms/Locations.svelte'
import ListCTAs from '$components/organisms/ListCTAs.svelte' import ListCTAs from '$components/organisms/ListCTAs.svelte'
@@ -147,7 +147,7 @@
</div> </div>
<section class="homepage__locations" id="locations"> <section class="homepage__locations" id="locations">
<InteractiveGlobe2 /> <InteractiveGlobe />
<ScrollingTitle tag="p" class="title-world mask"> <ScrollingTitle tag="p" class="title-world mask">
<SplitText text="World" mode="chars" /> <SplitText text="World" mode="chars" />

View File

@@ -14,7 +14,7 @@
import PageTransition from '$components/PageTransition.svelte' import PageTransition from '$components/PageTransition.svelte'
import Image from '$components/atoms/Image.svelte' import Image from '$components/atoms/Image.svelte'
import Heading from '$components/molecules/Heading.svelte' import Heading from '$components/molecules/Heading.svelte'
import InteractiveGlobe2 from '$components/organisms/InteractiveGlobe2.svelte' import InteractiveGlobe from '$components/organisms/InteractiveGlobe.svelte'
export let data: PageData export let data: PageData
const { credits, credit } = data const { credits, credit } = data
@@ -143,5 +143,5 @@
</div> </div>
</section> </section>
<InteractiveGlobe2 type="cropped" /> <InteractiveGlobe type="cropped" />
</PageTransition> </PageTransition>

View File

@@ -7,7 +7,7 @@
// Components // Components
import Metas from '$components/Metas.svelte' import Metas from '$components/Metas.svelte'
import PageTransition from '$components/PageTransition.svelte' import PageTransition from '$components/PageTransition.svelte'
import InteractiveGlobe2 from '$components/organisms/InteractiveGlobe2.svelte' import InteractiveGlobe from '$components/organisms/InteractiveGlobe.svelte'
import Locations from '$components/organisms/Locations.svelte' import Locations from '$components/organisms/Locations.svelte'
import ShopModule from '$components/organisms/ShopModule.svelte' import ShopModule from '$components/organisms/ShopModule.svelte'
import NewsletterModule from '$components/organisms/NewsletterModule.svelte' import NewsletterModule from '$components/organisms/NewsletterModule.svelte'
@@ -27,7 +27,7 @@
<Heading {text} /> <Heading {text} />
<section class="explore__locations"> <section class="explore__locations">
<InteractiveGlobe2 /> <InteractiveGlobe />
<Locations {locations} /> <Locations {locations} />
</section> </section>

View File

@@ -15,7 +15,7 @@
import Heading from '$components/molecules/Heading.svelte' import Heading from '$components/molecules/Heading.svelte'
import EmailForm from '$components/molecules/EmailForm.svelte' import EmailForm from '$components/molecules/EmailForm.svelte'
import NewsletterIssue from '$components/molecules/NewsletterIssue.svelte' import NewsletterIssue from '$components/molecules/NewsletterIssue.svelte'
import InteractiveGlobe2 from '$components/organisms/InteractiveGlobe2.svelte' import InteractiveGlobe from '$components/organisms/InteractiveGlobe.svelte'
export let data: PageData export let data: PageData
@@ -92,5 +92,5 @@
{/if} {/if}
</section> </section>
<InteractiveGlobe2 type="cropped" /> <InteractiveGlobe type="cropped" />
</PageTransition> </PageTransition>

View File

@@ -1,209 +1,188 @@
// Globe // Globe
.globe { .globe {
--width: clamp(700px, 100vw, 1315px);
position: relative;
z-index: 10;
user-select: none;
overflow: hidden;
// Canvas
&__canvas {
position: relative; position: relative;
z-index: 2; z-index: 2;
width: 1315px; left: 50%;
height: clamp(700px, 100vw, 1315px); transform: translateX(-50%) translateZ(0);
overflow: hidden; width: var(--width);
margin-left: auto;
margin-right: auto; // Responsive square padding
&:after {
content: "";
display: block;
padding-bottom: 100%;
}
// Overlay
&:before {
content: "";
display: block;
position: absolute;
z-index: 21;
top: 0;
left: 0;
width: 100%;
height: 100%;
opacity: 0;
pointer-events: none;
border-radius: 100%;
background: $color-primary;
transition: opacity 1.5s var(--ease-quart);
}
:global(canvas) {
position: absolute;
z-index: 10;
top: 0;
left: 0;
width: 100%;
height: 100%;
cursor: grab; cursor: grab;
}
// Is faded under name
&:global(.is-faded:before) {
opacity: 0.65;
}
}
// Location name
&__location {
position: absolute;
z-index: 30;
top: 50%;
left: 0;
width: 100%;
overflow: hidden;
transform: translateY(-50%) translateZ(0);
pointer-events: none;
text-align: center;
:global(.char) {
transition: none;
}
:global(.name) {
font-family: $font-serif;
font-weight: 100;
letter-spacing: -0.035em;
color: $color-secondary;
font-size: clamp(#{rem(88px)}, 20vw, #{rem(320px)});
}
.country {
display: block;
text-transform: uppercase;
font-size: rem(14px);
color: $color-tertiary;
letter-spacing: 0.1em;
font-weight: 500;
}
}
// Markers
&__markers {
position: relative;
z-index: 20;
pointer-events: none;
user-select: none; user-select: none;
// @include bp (sm) { li {
// height: 130vw; display: block;
// } margin: 0;
// @include bp (md) { padding: 0;
// height: 112vw; }
// } }
// @include bp (xl) {
// height: 100vw;
// }
// DEBUG // // Marker
// background: rgba(red, 0.2); &__marker {
// &:after { position: absolute;
// content: ""; top: 0;
// display: block; left: 0;
// position: absolute; user-select: none;
// top: 50%; transform: translate3d(var(--x), var(--y), 0);
// left: 0; transition: opacity 0.4s var(--ease-quart);
// background: blue;
// width: 100%; a {
// height: 2px; position: relative;
// margin-top: -1px; top: -10px;
// } left: -10px;
// END DEBUG // display: block;
width: 20px;
height: 20px;
display: flex;
align-items: center;
justify-content: center;
text-decoration: none;
color: $color-secondary;
pointer-events: auto;
// Dot
i {
display: block;
width: 10px;
height: 10px;
border-radius: 32px;
background: $color-secondary;
transition: box-shadow 0.4s var(--ease-quart), transform 0.4s var(--ease-quart);
transform-origin: 50% 50%;
}
// Name
span {
display: none;
}
// Hover: Grow marker outline
&:hover {
i {
box-shadow: 0 0 0 10px rgba($color-tertiary, 0.25);
}
}
}
// State: Is hidden
&:global(.is-hidden) {
opacity: 0;
i {
transform: scale(0) translateZ(0);
}
}
// State: Is disabled
&:global(.is-disabled a) {
pointer-events: none;
}
}
/* /*
** States and Variants ** States and Variants
*/ */
// When dragging // Cropped version
&:global(.is-grabbing) { &.is-cropped {
cursor: grabbing;
}
// Cropped globe
&-cropped {
overflow: hidden; overflow: hidden;
height: clamp(300px, 30vw, 500px); height: clamp(300px, 30vw, 500px);
} }
// When dragging
:global(.is-grabbing) {
cursor: grabbing;
} }
// Canvas // Tweakpane
:global(.globe-canvas) { :global(.tp-rotv) {
transition: opacity 0.2s var(--ease-quart);
// Hidden state
&:global(.is-hidden) {
opacity: 0;
transform: translate3d(0, 24px, 0);
}
}
/*
** Markers
*/
:global(.globe-markers) {
z-index: 2;
// Marker
:global(.marker) {
position: absolute;
z-index: 2;
cursor: pointer;
display: block;
top: -4px;
left: -4px;
padding: 4px;
opacity: 1;
will-change: transform;
// Dot
&:before {
content: "";
display: block;
position: absolute; position: absolute;
z-index: 10;
top: 0; top: 0;
left: 0; right: 0;
width: 8px; width: 300px;
height: 8px;
background: $color-secondary;
border-radius: 100%;
}
}
// Hover glow effect
:global(.hover) {
&:before {
animation: markerPulse 1s;
}
}
// Label
:global(.marker__label) {
position: absolute;
bottom: 16px;
left: 0px;
color: transparent;
pointer-events: none;
transition: color 0.4s var(--ease-quart), opacity 0.3s var(--ease-quart), transform 0.3s var(--ease-quart);
}
// Location city
:global(.marker__city) {
font-family: $font-serif;
font-size: rem(18px);
line-height: 1;
@include bp (sm) {
font-size: rem(24px);
}
}
// Location country
:global(.marker__country) {
display: block;
opacity: 0.8;
font-family: $font-sans;
font-size: rem(8px);
line-height: 1;
text-transform: uppercase;
letter-spacing: 1px;
@include bp (sm) {
font-size: rem(10px);
}
}
// Active
:global(.is-active) {
opacity: 1;
:global(span) {
opacity: 1;
}
:global(.marker__city) {
color: $color-secondary;
}
:global(.marker__country) {
color: $color-text;
}
}
// Is light
:global(.is-light) {
:global(.is-active) {
:global(.marker__city) {
color: #fff;
}
:global(.marker__country) {
color: #d2b7e4;
}
}
}
// Left positioned
:global(.is-left) {
:global(.marker__city) {
left: auto;
right: 32px;
}
:global(.marker__country) {
text-align: right;
}
}
// Marker is close to another one
// Show the marker infos only on hover
:global(.is-close) {
// Dot
&:before {
width: 7px;
height: 7px;
}
// Label
:global(.marker__label) {
opacity: 0;
transform: translate3d(0, 4px, 0);
}
// Show labels on hover
&:hover {
:global(.marker__label) {
opacity: 1;
transform: translate3d(0,0,0);
}
}
}
}
// Pulse animation
@keyframes markerPulse {
0% {
box-shadow: 0 0 0 0 rgba($color-secondary, 1);
}
100% {
box-shadow: 0 0 0 32px rgba(#fff, 0);
} }
} }

View File

@@ -1,188 +0,0 @@
// Globe
.globe {
--width: clamp(700px, 100vw, 1315px);
position: relative;
z-index: 10;
user-select: none;
overflow: hidden;
// Canvas
&__canvas {
position: relative;
z-index: 2;
left: 50%;
transform: translateX(-50%) translateZ(0);
width: var(--width);
// Responsive square padding
&:after {
content: "";
display: block;
padding-bottom: 100%;
}
// Overlay
&:before {
content: "";
display: block;
position: absolute;
z-index: 21;
top: 0;
left: 0;
width: 100%;
height: 100%;
opacity: 0;
pointer-events: none;
border-radius: 100%;
background: $color-primary;
transition: opacity 1.5s var(--ease-quart);
}
:global(canvas) {
position: absolute;
z-index: 10;
top: 0;
left: 0;
width: 100%;
height: 100%;
cursor: grab;
}
// Is faded under name
&:global(.is-faded:before) {
opacity: 0.65;
}
}
// Location name
&__location {
position: absolute;
z-index: 30;
top: 50%;
left: 0;
width: 100%;
overflow: hidden;
transform: translateY(-50%) translateZ(0);
pointer-events: none;
text-align: center;
:global(.char) {
transition: none;
}
:global(.name) {
font-family: $font-serif;
font-weight: 100;
letter-spacing: -0.035em;
color: $color-secondary;
font-size: clamp(#{rem(88px)}, 20vw, #{rem(320px)});
}
.country {
display: block;
text-transform: uppercase;
font-size: rem(14px);
color: $color-tertiary;
letter-spacing: 0.1em;
font-weight: 500;
}
}
// Markers
&__markers {
position: relative;
z-index: 20;
pointer-events: none;
user-select: none;
li {
display: block;
margin: 0;
padding: 0;
}
}
// Marker
&__marker {
position: absolute;
top: 0;
left: 0;
user-select: none;
transform: translate3d(var(--x), var(--y), 0);
transition: opacity 0.4s var(--ease-quart);
a {
position: relative;
top: -10px;
left: -10px;
display: block;
width: 20px;
height: 20px;
display: flex;
align-items: center;
justify-content: center;
text-decoration: none;
color: $color-secondary;
pointer-events: auto;
// Dot
i {
display: block;
width: 10px;
height: 10px;
border-radius: 32px;
background: $color-secondary;
transition: box-shadow 0.4s var(--ease-quart), transform 0.4s var(--ease-quart);
transform-origin: 50% 50%;
}
// Name
span {
display: none;
}
// Hover: Grow marker outline
&:hover {
i {
box-shadow: 0 0 0 10px rgba($color-tertiary, 0.25);
}
}
}
// State: Is hidden
&:global(.is-hidden) {
opacity: 0;
i {
transform: scale(0) translateZ(0);
}
}
// State: Is disabled
&:global(.is-disabled a) {
pointer-events: none;
}
}
/*
** States and Variants
*/
// Cropped version
&.is-cropped {
overflow: hidden;
height: clamp(300px, 30vw, 500px);
}
// When dragging
:global(.is-grabbing) {
cursor: grabbing;
}
// Tweakpane
:global(.tp-rotv) {
position: absolute;
z-index: 10;
top: 0;
right: 0;
width: 300px;
}
}

View File

@@ -119,25 +119,6 @@ export const getRandomItems = <T extends unknown> (array: any[], amount: number)
} }
/**
* Get a DOM element's position
*/
export const getPosition = (node: any, scope?: HTMLElement) => {
const root = scope || document
let offsetTop = node.offsetTop
let 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
}
}
/** /**
* Scroll back to top after page transition * Scroll back to top after page transition
*/ */