Remove old Globe
This commit is contained in:
@@ -3,140 +3,159 @@
|
||||
</style>
|
||||
|
||||
<script lang="ts">
|
||||
import { onMount, getContext } from 'svelte'
|
||||
import { getPosition, getRandomItem } from '$utils/functions'
|
||||
import { getContext, onMount } from 'svelte'
|
||||
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 autoRotate: boolean = true
|
||||
export let scrollSmooth: number = 0.5
|
||||
export let opacity: number = 1
|
||||
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 InteractiveGlobe: any
|
||||
let globeEl: HTMLElement
|
||||
let observer: IntersectionObserver
|
||||
let globe: any
|
||||
let innerWidth: number
|
||||
let innerHeight: number
|
||||
let containerTop = 0
|
||||
let containerHeight = 0
|
||||
|
||||
$: globeResolution = innerWidth > 1440 && window.devicePixelRatio > 1 ? '4k' : '2k'
|
||||
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.filter((cont: any) => cont.countries))
|
||||
const markers = locations.map(({ name, slug, country, globe_close: isClose, coordinates: { coordinates }}: any) => ({
|
||||
const randomContinent: any = getRandomItem(continents)
|
||||
const markers = locations.map(({ name, slug, country, coordinates: { coordinates }}): Marker => ({
|
||||
name,
|
||||
slug,
|
||||
countryName: country.name,
|
||||
countrySlug: country.slug,
|
||||
country: { ...country },
|
||||
lat: coordinates[1],
|
||||
lng: coordinates[0],
|
||||
className: isClose ? 'is-close' : '',
|
||||
}))
|
||||
|
||||
|
||||
/*
|
||||
** Functions
|
||||
*/
|
||||
// Globe update
|
||||
const update = () => {
|
||||
requestAnimationFrame(update)
|
||||
globe.update()
|
||||
}
|
||||
onMount(() => {
|
||||
const globeResolution = innerWidth > 1440 && window.devicePixelRatio > 1 ? 4 : 2
|
||||
|
||||
// On scroll
|
||||
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({
|
||||
globe = new Globe({
|
||||
el: globeEl,
|
||||
//cameraDistance: size, // Smaller number == larger globe
|
||||
autoRotationSpeed: autoRotate ? -0.0025 : 0,
|
||||
rotationStart: randomContinent.rotation, // In degrees
|
||||
scrollSmoothing: scrollSmooth,
|
||||
opacity: opacity,
|
||||
texture: `/images/globe-map-${globeResolution}.png`,
|
||||
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: enableMarkersLinks && type !== 'cropped',
|
||||
markers,
|
||||
onLinkClicked: () => {}
|
||||
pane,
|
||||
})
|
||||
|
||||
// Run the globe
|
||||
update()
|
||||
setTimeout(() => {
|
||||
handleResize()
|
||||
handleScroll()
|
||||
}, 1000)
|
||||
resize()
|
||||
|
||||
|
||||
// Enable/Disable the globe when shown/hidden
|
||||
const globeCanvas = document.querySelector('.globe-canvas')
|
||||
|
||||
observer = new IntersectionObserver(entries => {
|
||||
entries.forEach(({ isIntersecting }: IntersectionObserverEntry) => {
|
||||
// Render only if in viewport
|
||||
observer = new IntersectionObserver(([{ isIntersecting }]) => {
|
||||
if (isIntersecting) {
|
||||
globe.enable()
|
||||
globeCanvas.classList.remove('is-hidden')
|
||||
} else {
|
||||
globe.disable()
|
||||
globeCanvas.classList.add('is-hidden')
|
||||
update()
|
||||
|
||||
if (isDev) {
|
||||
console.log('globe: render/start')
|
||||
}
|
||||
})
|
||||
}, {
|
||||
threshold: 0,
|
||||
rootMargin: '0px 0px 0px'
|
||||
})
|
||||
} else {
|
||||
stop()
|
||||
|
||||
if (isDev) {
|
||||
console.log('globe: render/stop')
|
||||
}
|
||||
}
|
||||
}, { threshold: 0 })
|
||||
observer.observe(globeEl)
|
||||
|
||||
|
||||
// Destroy
|
||||
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>
|
||||
|
||||
<svelte:window
|
||||
on:scroll={handleScroll}
|
||||
on:resize={handleResize}
|
||||
bind:innerHeight
|
||||
bind:innerWidth
|
||||
<svelte:window bind:innerWidth
|
||||
on:resize={resize}
|
||||
/>
|
||||
|
||||
|
||||
<section id="globe">
|
||||
{#if type === 'cropped'}
|
||||
<div class="globe-cropped">
|
||||
<div class="globe" bind:this={globeEl} />
|
||||
<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>
|
||||
{:else}
|
||||
<div class="globe" bind:this={globeEl} />
|
||||
{/if}
|
||||
</section>
|
||||
</div>
|
||||
@@ -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>
|
||||
@@ -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;
|
||||
@@ -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;
|
||||
@@ -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;
|
||||
@@ -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;
|
||||
@@ -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;
|
||||
@@ -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;
|
||||
@@ -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;
|
||||
@@ -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;
|
||||
@@ -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;
|
||||
@@ -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;
|
||||
@@ -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;
|
||||
@@ -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;
|
||||
@@ -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));
|
||||
}
|
||||
@@ -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;
|
||||
@@ -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;
|
||||
@@ -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
@@ -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));
|
||||
};
|
||||
})();
|
||||
@@ -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;
|
||||
};
|
||||
})();
|
||||
@@ -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;
|
||||
};
|
||||
})();
|
||||
@@ -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;
|
||||
};
|
||||
})();
|
||||
@@ -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';
|
||||
@@ -1,8 +0,0 @@
|
||||
precision highp float;
|
||||
|
||||
uniform float alpha;
|
||||
varying vec2 vUv;
|
||||
|
||||
void main(void) {
|
||||
gl_FragColor = vec4( vec3(1., 1., 1.), alpha);
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
@@ -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;
|
||||
|
||||
}
|
||||
@@ -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;
|
||||
@@ -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 );
|
||||
}
|
||||
@@ -1,3 +0,0 @@
|
||||
export default function isPowerOf2(value) {
|
||||
return (value & (value - 1)) == 0;
|
||||
}
|
||||
@@ -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( '' );
|
||||
}
|
||||
@@ -1,3 +0,0 @@
|
||||
export default function warn(msg, ctx){
|
||||
console.log("%c" + "[warn]: " + msg, "color:#ff0084", ctx );
|
||||
}
|
||||
@@ -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.);
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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
|
||||
@@ -3,8 +3,8 @@ import { Renderer, Camera, Vec3, Orbit, Sphere, Transform, Program, Mesh, Textur
|
||||
import SunCalc from 'suncalc'
|
||||
import { map } from '$utils/functions/index'
|
||||
// Shaders
|
||||
import VERTEX_SHADER from '$modules/globe2/vertex.glsl?raw'
|
||||
import FRAGMENT_SHADER from '$modules/globe2/frag.glsl?raw'
|
||||
import VERTEX_SHADER from '$modules/globe/vertex.glsl?raw'
|
||||
import FRAGMENT_SHADER from '$modules/globe/frag.glsl?raw'
|
||||
|
||||
|
||||
export class Globe {
|
||||
@@ -10,7 +10,7 @@
|
||||
import PageTransition from '$components/PageTransition.svelte'
|
||||
import BoxCTA from '$components/atoms/BoxCTA.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 Locations from '$components/organisms/Locations.svelte'
|
||||
import ShopModule from '$components/organisms/ShopModule.svelte'
|
||||
@@ -68,7 +68,7 @@
|
||||
</ListCTAs>
|
||||
</div>
|
||||
|
||||
<InteractiveGlobe2 />
|
||||
<InteractiveGlobe />
|
||||
<Locations {locations} />
|
||||
|
||||
<div class="grid-modules">
|
||||
|
||||
@@ -21,7 +21,7 @@
|
||||
import ScrollingTitle from '$components/atoms/ScrollingTitle.svelte'
|
||||
import BoxCTA from '$components/atoms/BoxCTA.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 Locations from '$components/organisms/Locations.svelte'
|
||||
import ListCTAs from '$components/organisms/ListCTAs.svelte'
|
||||
@@ -147,7 +147,7 @@
|
||||
</div>
|
||||
|
||||
<section class="homepage__locations" id="locations">
|
||||
<InteractiveGlobe2 />
|
||||
<InteractiveGlobe />
|
||||
|
||||
<ScrollingTitle tag="p" class="title-world mask">
|
||||
<SplitText text="World" mode="chars" />
|
||||
|
||||
@@ -14,7 +14,7 @@
|
||||
import PageTransition from '$components/PageTransition.svelte'
|
||||
import Image from '$components/atoms/Image.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
|
||||
const { credits, credit } = data
|
||||
@@ -143,5 +143,5 @@
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<InteractiveGlobe2 type="cropped" />
|
||||
<InteractiveGlobe type="cropped" />
|
||||
</PageTransition>
|
||||
@@ -7,7 +7,7 @@
|
||||
// Components
|
||||
import Metas from '$components/Metas.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 ShopModule from '$components/organisms/ShopModule.svelte'
|
||||
import NewsletterModule from '$components/organisms/NewsletterModule.svelte'
|
||||
@@ -27,7 +27,7 @@
|
||||
<Heading {text} />
|
||||
|
||||
<section class="explore__locations">
|
||||
<InteractiveGlobe2 />
|
||||
<InteractiveGlobe />
|
||||
<Locations {locations} />
|
||||
</section>
|
||||
|
||||
|
||||
@@ -15,7 +15,7 @@
|
||||
import Heading from '$components/molecules/Heading.svelte'
|
||||
import EmailForm from '$components/molecules/EmailForm.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
|
||||
|
||||
@@ -92,5 +92,5 @@
|
||||
{/if}
|
||||
</section>
|
||||
|
||||
<InteractiveGlobe2 type="cropped" />
|
||||
<InteractiveGlobe type="cropped" />
|
||||
</PageTransition>
|
||||
@@ -1,209 +1,188 @@
|
||||
// Globe
|
||||
.globe {
|
||||
--width: clamp(700px, 100vw, 1315px);
|
||||
position: relative;
|
||||
z-index: 10;
|
||||
user-select: none;
|
||||
overflow: hidden;
|
||||
|
||||
// Canvas
|
||||
&__canvas {
|
||||
position: relative;
|
||||
z-index: 2;
|
||||
width: 1315px;
|
||||
height: clamp(700px, 100vw, 1315px);
|
||||
overflow: hidden;
|
||||
margin-left: auto;
|
||||
margin-right: auto;
|
||||
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;
|
||||
|
||||
// @include bp (sm) {
|
||||
// height: 130vw;
|
||||
// }
|
||||
// @include bp (md) {
|
||||
// height: 112vw;
|
||||
// }
|
||||
// @include bp (xl) {
|
||||
// height: 100vw;
|
||||
// }
|
||||
li {
|
||||
display: block;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
}
|
||||
}
|
||||
|
||||
// DEBUG //
|
||||
// background: rgba(red, 0.2);
|
||||
// &:after {
|
||||
// content: "";
|
||||
// display: block;
|
||||
// position: absolute;
|
||||
// top: 50%;
|
||||
// left: 0;
|
||||
// background: blue;
|
||||
// width: 100%;
|
||||
// height: 2px;
|
||||
// margin-top: -1px;
|
||||
// }
|
||||
// END DEBUG //
|
||||
// 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
|
||||
*/
|
||||
// When dragging
|
||||
&:global(.is-grabbing) {
|
||||
cursor: grabbing;
|
||||
}
|
||||
|
||||
// Cropped globe
|
||||
&-cropped {
|
||||
// Cropped version
|
||||
&.is-cropped {
|
||||
overflow: hidden;
|
||||
height: clamp(300px, 30vw, 500px);
|
||||
}
|
||||
}
|
||||
|
||||
// Canvas
|
||||
:global(.globe-canvas) {
|
||||
transition: opacity 0.2s var(--ease-quart);
|
||||
|
||||
// Hidden state
|
||||
&:global(.is-hidden) {
|
||||
opacity: 0;
|
||||
transform: translate3d(0, 24px, 0);
|
||||
// When dragging
|
||||
:global(.is-grabbing) {
|
||||
cursor: grabbing;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
** 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;
|
||||
// Tweakpane
|
||||
:global(.tp-rotv) {
|
||||
position: absolute;
|
||||
z-index: 10;
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 8px;
|
||||
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);
|
||||
right: 0;
|
||||
width: 300px;
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -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
|
||||
*/
|
||||
|
||||
Reference in New Issue
Block a user