WIP Interactive globe from Nico's sources

- The globe is a bit small? Ability to control the max-min size potentially
- Is there a reason why `globe.update()` runs every second? Sounds like a lot of resources?
- Have the ability to control the `addEventListener` of the markers to do whatever (in this case, going to a route by clicking on a link with a sapper-noscroll attribute + changing the href attribute on click - the method `goto` from Sapper scrolls back to top / maybe something to fix with the current transition issues?)
- Edited in `./index.js`:
    1. Using the class as `export default WebglGlobe` instead of Window (as Svelte or Sapper doesn't likayt)
- Edited in `Camera.js`:
    1. Commented line 218: `e.preventDefault();` would cause this error: `[Intervention] Unable to preventDefault inside passive event listener due to target being treated as passive. See <URL>`
This commit is contained in:
2020-04-02 20:55:20 +02:00
parent 730eb75457
commit 2064885997
73 changed files with 15339 additions and 137 deletions

26
src/globe/beam/ArrayBuffer.js Executable file
View File

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

View File

@@ -0,0 +1,120 @@
import GeometryBuffer from './GeometryBuffer';
import * as vec3 from './glMatrix/vec3';
class BoxGeometryBuffer extends GeometryBuffer {
constructor(gl, options) {
super(gl, 4.);
options = Object.assign({},{
width: 10,
height: 10,
depth: 10,
widthSegments: 1,
heightSegments: 1,
depthSegments: 1
}, options);
// buffers
var indices = [];
var vertices = [];
var normals = [];
var uvs = [];
var colors = []
var numberOfVertices = 0;
var vertexCounter = 0;
function buildPlane( u, v, w, udir, vdir, width, height, depth, gridX, gridY ) {
vertexCounter = 0;
var segmentWidth = width / gridX;
var segmentHeight = height / gridY;
var widthHalf = width / 2;
var heightHalf = height / 2;
var depthHalf = depth / 2;
var gridX1 = gridX + 1;
var gridY1 = gridY + 1;
var ix, iy;
var vector = vec3.create();
// generate vertices, normals and uvs
for ( iy = 0; iy < gridY1; iy ++ ) {
var y = iy * segmentHeight - heightHalf;
for ( ix = 0; ix < gridX1; ix ++ ) {
var x = ix * segmentWidth - widthHalf;
vector[ u ] = x * udir;
vector[ v ] = y * vdir;
vector[ w ] = depthHalf;
vertices.push( vector[0], vector[1], vector[2] );
vector[ u ] = 1.;
vector[ v ] = 1.;
vector[ w ] = 1.;
vector[ u ] = 0;
vector[ v ] = 0;
vector[ w ] = depth > 0 ? 1 : -1;
normals.push( vector[0], vector[1], vector[2] );
uvs.push( ix / gridX, 1 - ( iy / gridY ) );
colors.push( 1, 1, 1 );
vertexCounter += 1;
}
}
for ( iy = 0; iy < gridY; iy ++ ) {
for ( ix = 0; ix < gridX; ix ++ ) {
var a = numberOfVertices + ix + gridX1 * iy;
var b = numberOfVertices + ix + gridX1 * ( iy + 1 );
var c = numberOfVertices + ( ix + 1 ) + gridX1 * ( iy + 1 );
var d = numberOfVertices + ( ix + 1 ) + gridX1 * iy;
// faces
indices.push( a, b, d );
indices.push( b, c, d );
}
}
numberOfVertices += vertexCounter;
}
// build each side of the box geometry
buildPlane( 2, 1, 0, - 1, - 1, options.depth, options.height, options.width, Math.floor(options.depthSegments), Math.floor(options.heightSegments) ); // px
buildPlane( 2, 1, 0, 1, - 1, options.depth, options.height, - options.width, Math.floor(options.depthSegments), Math.floor(options.heightSegments) ); // nx
buildPlane( 0, 2, 1, 1, 1, options.width, options.depth, options.height, Math.floor(options.widthSegments), Math.floor(options.depthSegments) ); // py
buildPlane( 0, 2, 1, 1, - 1, options.width, options.depth, - options.height, Math.floor(options.widthSegments), Math.floor(options.depthSegments) ); // ny
buildPlane( 0, 1, 2, 1, - 1, options.width, options.height, options.depth, Math.floor(options.widthSegments), Math.floor(options.heightSegments) ); // pz
buildPlane( 0, 1, 2, - 1, - 1, options.width, options.height, - options.depth, Math.floor(options.widthSegments), Math.floor(options.heightSegments) ); // nz
// build geometry
this.length = numberOfVertices;
this.addAttribute( 'index', new Uint16Array( indices ), 1 );
this.addAttribute( 'position', new Float32Array( vertices ), 3 );
this.addAttribute( 'normal', new Float32Array( normals ), 3 );
this.addAttribute( 'uv', new Float32Array( uvs ), 2 );
this.addAttribute( 'color', new Float32Array( colors ), 3 );
}
}
export default BoxGeometryBuffer;

393
src/globe/beam/Camera.js Executable file
View File

@@ -0,0 +1,393 @@
import Object3d from './Object3d';
import Container from './Container';
import * as mat4 from './glMatrix/mat4';
import * as vec3 from './glMatrix/vec3';
import * as quat from './glMatrix/quat';
const TOUCH = ('ontouchstart' in window) || (navigator.msMaxTouchPoints > 0);
const POINTER = !!window.navigator.pointerEnabled;
const MS_POINTER = !!window.navigator.msPointerEnabled;
const POINTER_DOWN = TOUCH ? 'touchstart' : (POINTER ? 'pointerdown' : (MS_POINTER ? 'MSPointerDown' : 'mousedown' ) );
const POINTER_MOVE = TOUCH ? 'touchmove' : (POINTER ? 'pointermove' : (MS_POINTER ? 'MSPointerMove' : 'mousemove' ) );
const POINTER_UP = TOUCH ? 'touchend' : (POINTER ? 'pointerup' : (MS_POINTER ? 'MSPointerUp' : 'mouseup' ) );
var objects = []
function needsUpdateLoop() {
requestAnimationFrame(needsUpdateLoop);
for (let i=0; i<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.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 ) );
}
}
_onPointerUp() {
this._isPointerDown = false;
this.isRightClick = false;
}
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;
this.lookAt[0] = 0.000000001//this.pointerXMove / -100;
this.lookAt[1] = 0.000000001//this.pointerYMove / 100;
this.lookAt[2] = 0.000000001
super.render();
}
}
else if (this.firstPerson)
{
if (this._canUpdate || force) {
var time = Date.now();
var delta = ( time - this.time ) / 1000;
this.prevTime = time;
this._velocity[0] -= this._velocity[0] * 10.0 * delta;
this._velocity[1] -= this._velocity[1] * 10.0 * delta;
this._velocity[2] -= this._velocity[2] * 10.0 * delta;
if (this.position[1] < 0 && this._velocity[1] < 0) {
this._velocity[1] = 0;
this.position[1] = 0
}
if ( this._moveForward ) this._velocity[2] -= (this.moveSpeed) * delta;
if ( this._moveBackward ) this._velocity[2] += (this.moveSpeed) * delta;
if ( this._moveLeft ) this._velocity[0] -= (this.moveSpeed) * delta;
if ( this._moveRight ) this._velocity[0] += (this.moveSpeed) * delta;
this._camera[0] = this._velocity[0];
this._camera[1] = this._velocity[1];
this._camera[2] = this._velocity[2];
this.currTheta += (this.theta - this.currTheta) * 0.2;
this.currPhi += (this.phi - this.currPhi) * 0.2;
//first we reset position to center and rotate the camera
this._oldPosition[0] = this.position[0];
this._oldPosition[1] = this.position[1];
this._oldPosition[2] = this.position[2];
this.position[0] = 0;
this.position[1] = 0;
this.position[2] = 0;
this.lookAt[0] = Math.sin(this.currTheta) * Math.cos(this.currPhi) * this._cameraDistance ;
this.lookAt[1] = Math.sin(this.currPhi) * this._cameraDistance * -1 ;
this.lookAt[2] = Math.cos(this.currTheta) * Math.cos(this.currPhi) * this._cameraDistance ;
this.updateMatrix()
//then we translate the camera based on velocity to folow view direction
var _matrix = mat4.create();
mat4.copy(_matrix, this.matrix);
mat4.translate( _matrix, _matrix, this._camera);
var _pos = vec3.create()
mat4.getTranslation(_pos, _matrix);
this.position[0] = this._oldPosition[0] + _pos[0]
this.position[1] = this._oldPosition[1] + _pos[1]
this.position[2] = this._oldPosition[2] + _pos[2]
this.lookAt[0] = Math.sin(this.currTheta) * Math.cos(this.currPhi) * this._cameraDistance + this.position[0];
this.lookAt[1] = Math.sin(this.currPhi) * this._cameraDistance * -1 + this.position[1];
this.lookAt[2] = Math.cos(this.currTheta) * Math.cos(this.currPhi) * this._cameraDistance + this.position[2];
this.updateMatrix();
this.updateWorldMatrix();
this.time = time;
}
}
else {
super.render();
}
this._canUpdate = false;
}
}
export default Camera;

53
src/globe/beam/Container.js Executable file
View File

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

155
src/globe/beam/CubeTexture.js Executable file
View File

@@ -0,0 +1,155 @@
import uuid from './utils/uuid';
import getFilter from './utils/getFilter';
import isPowerOf2 from './utils/isPowerOf2';
class CubeTexture {
constructor(gl, options) {
options = Object.assign({}, {
format: gl.RGBA,
type: gl.UNSIGNED_BYTE,
width: 1,
height: 1,
linear: true,
mipmap: false,
miplinear: false,
wrapS: gl.CLAMP_TO_EDGE,
wrapT: gl.CLAMP_TO_EDGE,
urls: null
}, options);
this._uid = uuid();//debug purpose
this.gl = gl;
this.width = options.width;
this.height = options.height;
this.format = options.format;
this.type = options.type;
var floatTextures = gl.getExtension('OES_texture_float');
var floatTextureLinearFiltering = gl.getExtension('OES_texture_float_linear');
if (!floatTextures) {
throw('trying to create a FrameBuffer of with gl.FLOAT type but there\s no floating point texture support');
return;
}
this._texture = this.gl.createTexture();
gl.bindTexture( gl.TEXTURE_CUBE_MAP, this._texture);
gl.texParameteri(gl.TEXTURE_CUBE_MAP, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE);
gl.texParameteri(gl.TEXTURE_CUBE_MAP, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE);
gl.texParameteri(gl.TEXTURE_CUBE_MAP, gl.TEXTURE_MIN_FILTER, gl.LINEAR);
gl.texParameteri(gl.TEXTURE_CUBE_MAP, gl.TEXTURE_MAG_FILTER, gl.LINEAR);
gl.texImage2D(gl.TEXTURE_CUBE_MAP_POSITIVE_X, 0, this.format, this.width, this.height, 0, this.format, this.type, new Uint8Array(new Array(this.width*this.height*4)));
gl.texImage2D(gl.TEXTURE_CUBE_MAP_NEGATIVE_X, 0, this.format, this.width, this.height, 0, this.format, this.type, new Uint8Array(new Array(this.width*this.height*4)));
gl.texImage2D(gl.TEXTURE_CUBE_MAP_POSITIVE_Y, 0, this.format, this.width, this.height, 0, this.format, this.type, new Uint8Array(new Array(this.width*this.height*4)));
gl.texImage2D(gl.TEXTURE_CUBE_MAP_NEGATIVE_Y, 0, this.format, this.width, this.height, 0, this.format, this.type, new Uint8Array(new Array(this.width*this.height*4)));
gl.texImage2D(gl.TEXTURE_CUBE_MAP_POSITIVE_Z, 0, this.format, this.width, this.height, 0, this.format, this.type, new Uint8Array(new Array(this.width*this.height*4)));
gl.texImage2D(gl.TEXTURE_CUBE_MAP_NEGATIVE_Z, 0, this.format, this.width, this.height, 0, this.format, this.type, new Uint8Array(new Array(this.width*this.height*4)));
gl.bindTexture( gl.TEXTURE_CUBE_MAP, null);
// /**
// * add getter and setter to update texture_wrap when this.wrap changes
// */
// Object.defineProperty(this, 'wrapS', {
// set: (value) => {
// this.gl.bindTexture( this.gl.TEXTURE_CUBE_MAP, this._texture);
// this.gl.texParameteri( this.gl.TEXTURE_CUBE_MAP, this.gl.TEXTURE_WRAP_S, value );
// }
// });
// Object.defineProperty(this, 'wrapT', {
// set: (value) => {
// this.gl.bindTexture( this.gl.TEXTURE_CUBE_MAP, this._texture);
// this.gl.texParameteri( this.gl.TEXTURE_CUBE_MAP, this.gl.TEXTURE_WRAP_T, value );
// }
// });
// //nPOT texture can't repeat
// this.wrapS = options.wrapS;
// this.wrapT = options.wrapT;
//nPOT texture cannot mipmap
// this.setFilter( options.linear, options.mipmap, options.mipmapLinear );
if (options.urls !== null) {
this.load(options.urls);
}
}
load(urls) {
var faces = [
this.gl.TEXTURE_CUBE_MAP_POSITIVE_X,
this.gl.TEXTURE_CUBE_MAP_NEGATIVE_X,
this.gl.TEXTURE_CUBE_MAP_POSITIVE_Y,
this.gl.TEXTURE_CUBE_MAP_NEGATIVE_Y,
this.gl.TEXTURE_CUBE_MAP_POSITIVE_Z,
this.gl.TEXTURE_CUBE_MAP_NEGATIVE_Z
];
for (let i = 0; i < urls.length; i++) {
let face = faces[i];
let image = new Image();
image.onload = ()=> {
image.onload = null;
// this.bindFaceImage(face, image);
this.gl.bindTexture(this.gl.TEXTURE_CUBE_MAP, this._texture);
this.gl.pixelStorei(this.gl.UNPACK_FLIP_Y_WEBGL, false);
this.gl.texImage2D(face, 0, this.gl.RGBA, this.gl.RGBA, this.gl.UNSIGNED_BYTE, image);
this.gl.texParameteri(this.gl.TEXTURE_CUBE_MAP, this.gl.TEXTURE_MAG_FILTER, this.gl.LINEAR);
this.gl.texParameteri(this.gl.TEXTURE_CUBE_MAP, this.gl.TEXTURE_MIN_FILTER, this.gl.LINEAR);
this.gl.texParameteri(this.gl.TEXTURE_CUBE_MAP, this.gl.TEXTURE_WRAP_S, this.gl.CLAMP_TO_EDGE);
this.gl.texParameteri(this.gl.TEXTURE_CUBE_MAP, this.gl.TEXTURE_WRAP_T, this.gl.CLAMP_TO_EDGE);
}
image.src = urls[i];
}
}
bindFaceImage(face, image) {
this.gl.bindTexture(this.gl.TEXTURE_CUBE_MAP, this._texture);
this.gl.pixelStorei(this.gl.UNPACK_FLIP_Y_WEBGL, false);
if (image._texture) {
this.gl.texImage2D(face, 0, this.format, image.width, image.height, 0, this.format, this.type, image._texture);
}
else {
this.gl.texImage2D(face, 0, this.format, image.width, image.height, 0, this.format, this.type, image);
}
}
bindFaceFrameBuffer(face, frameBuffer) {
this.gl.bindTexture( this.gl.TEXTURE_CUBE_MAP, this._texture);
this.gl.bindFramebuffer( this.gl.FRAMEBUFFER, frameBuffer.fbo );
this.gl.framebufferTexture2D(this.gl.FRAMEBUFFER, this.gl.COLOR_ATTACHMENT0, face, this._texture, 0);
let status_code = this.gl.checkFramebufferStatus(this.gl.FRAMEBUFFER);
if (status_code != this.gl.FRAMEBUFFER_COMPLETE) {
if (status_code == this.gl.FRAMEBUFFER_INCOMPLETE_ATTACHMENT) {
console.log('GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT');
}
if (status_code == this.gl.FRAMEBUFFER_INCOMPLETE_DIMENSIONS) {
console.log('FRAMEBUFFER_INCOMPLETE_DIMENSIONS: Not all attached images have the same width and height.');
}
if (status_code == this.gl.FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT) {
console.log('FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT: No images are attached to the framebuffer.');
}
} else {
console.log("success");
}
// this.gl.bindTexture( this.gl.TEXTURE_CUBE_MAP, null );
this.gl.bindFramebuffer( this.gl.FRAMEBUFFER, null );
frameBuffer.unbind();
}
bind(unit) {
if( unit !== undefined ){
this.gl.activeTexture( this.gl.TEXTURE0 + (0|unit) );
}
this.gl.bindTexture( this.gl.TEXTURE_CUBE_MAP, this._texture );
}
delete() {
this.gl.deleteTexture( this._texture );
this._texture = null;
this.gl = null;
}
}
export default CubeTexture;

64
src/globe/beam/DepthTexture.js Executable file
View File

@@ -0,0 +1,64 @@
class DepthTexture {
constructor(gl, options) {
let supportsDepthTexture = gl.getExtension("WEBGL_depth_texture");
if (!supportsDepthTexture) {
throw("FrameBuffer useDepthTexture:true => Cannot render depth to texture, the browser doesnt support WEBKIT_WEBGL_depth_texture extension")
}
options = Object.assign({}, {
width: 1,
height: 1,
type: gl.UNSIGNED_SHORT
}, options);
this.gl = gl;
this.width = options.width;
this.height = options.height;
this.type = options.type;
var floatTextures = gl.getExtension('OES_texture_float');
var floatTextureLinearFiltering = gl.getExtension('OES_texture_float_linear');
if (!floatTextures && this.type == gl.FLOAT) {
throw('trying to create a DepthTexture of gl.FLOAT type but there\s no floating point texture support');
return;
}
this._texture = this.gl.createTexture();
this.gl.bindTexture(this.gl.TEXTURE_2D, this._texture);
this.gl.texParameteri(this.gl.TEXTURE_2D, this.gl.TEXTURE_MAG_FILTER, this.gl.NEAREST);
this.gl.texParameteri(this.gl.TEXTURE_2D, this.gl.TEXTURE_MIN_FILTER, this.gl.NEAREST);
this.gl.texParameteri(this.gl.TEXTURE_2D, this.gl.TEXTURE_WRAP_S, this.gl.CLAMP_TO_EDGE);
this.gl.texParameteri(this.gl.TEXTURE_2D, this.gl.TEXTURE_WRAP_T, this.gl.CLAMP_TO_EDGE);
this.gl.texImage2D(this.gl.TEXTURE_2D, 0, this.gl.DEPTH_COMPONENT, this.width, this.height, 0, this.gl.DEPTH_COMPONENT, this.type, null);
gl.bindTexture( gl.TEXTURE_2D, null);
}
bind(unit) {
if (unit !== void 0) {
this.gl.activeTexture( this.gl.TEXTURE0 + (0|unit) );
}
this.gl.bindTexture(this.gl.TEXTURE_2D, this._texture);
}
delete() {
this.gl.deleteTexture( this._texture );
this._texture = null;
this.gl = null;
}
resize(w, h) {
this.width = w;
this.height = h;
this.gl.bindTexture(this.gl.TEXTURE_2D, this._texture);
this.gl.texImage2D(this.gl.TEXTURE_2D, 0, this.gl.DEPTH_COMPONENT, this.width, this.height, 0, this.gl.DEPTH_COMPONENT, this.type, null);
gl.bindTexture( gl.TEXTURE_2D, null);
}
}
export default DepthTexture;

231
src/globe/beam/FrameBuffer.js Executable file
View File

@@ -0,0 +1,231 @@
import getFilter from './utils/getFilter';
import isPowerOf2 from './utils/isPowerOf2';
class FrameBuffer {
constructor ( gl, options ) {
this.options = Object.assign({},{
format: gl.RGBA,
type: gl.UNSIGNED_BYTE,
linear: true,
mipmap: false,
mipmapLinear: false,
wrapS: gl.CLAMP_TO_EDGE,
wrapT: gl.CLAMP_TO_EDGE,
depthTexture: null
}, options);
this.gl = gl;
this.width = this.options.width;
this.height = this.options.height;
this.format = this.options.format;
this.type = this.options.type;
this.linear = this.options.linear;
this.mipmap = this.options.mipmap;
this.mipmapLinear = this.options.mipmapLinear;
if (this.type == gl.FLOAT) {
var floatTextures = gl.getExtension('OES_texture_float');
var floatTextureLinearFiltering = gl.getExtension('OES_texture_float_linear');
if (!floatTextures) {
console.warn('trying to create a FrameBuffer of with gl.FLOAT type but there\s no floating point texture support. trying HALF_FLOAT');
this.type = "HALF_FLOAT"
}
}
if (this.type == "HALF_FLOAT") {
var halfFloatTexturesExt = gl.getExtension('OES_texture_half_float');
var halfFloatTextureLinearFiltering = gl.getExtension('OES_texture_half_float_linear');
if (!halfFloatTexturesExt) {
console.warn('trying to create a texture of with gl.HALF_FLOAT type but there\s no half floating point texture support; falling bck to UNSIGNED_BYTE type');
this.type = gl.UNSIGNED_BYTE;
}
else {
this.type = halfFloatTexturesExt.HALF_FLOAT_OES;
this.isHalfFloat = true;
}
}
this._texture = this.gl.createTexture();
this.gl.bindTexture(this.gl.TEXTURE_2D, this._texture);
if (this.type == this.gl.FLOAT) {
this.gl.texImage2D(this.gl.TEXTURE_2D, 0, this.format, this.width, this.height, 0, this.format, this.type, new Float32Array( new Array(this.width * this.height * 4) ));
}
else if (this.isHalfFloat) {
this.gl.texImage2D(this.gl.TEXTURE_2D, 0, this.format, this.width, this.height, 0, this.format, this.type, null);
}
else {
this.gl.texImage2D(this.gl.TEXTURE_2D, 0, this.format, this.width, this.height, 0, this.format, this.type, new Uint8Array( new Array(this.width * this.height * 4) ));
}
/**
* add getter and setter to update texture_wrap when this.wrap changes
*/
Object.defineProperty(this, 'wrapS', {
set: (value) => {
this.gl.bindTexture(this.gl.TEXTURE_2D, this._texture);
this.gl.texParameteri( this.gl.TEXTURE_2D, this.gl.TEXTURE_WRAP_S, value );
}
});
Object.defineProperty(this, 'wrapT', {
set: (value) => {
this.gl.bindTexture(this.gl.TEXTURE_2D, this._texture);
this.gl.texParameteri( this.gl.TEXTURE_2D, this.gl.TEXTURE_WRAP_T, value );
}
});
//nPOT texture can't repeat
this.wrapS = this.options.wrapS;
this.wrapT = this.options.wrapT;
var isPOT = isPowerOf2(this.width) && isPowerOf2(this.height);
if (!isPOT) {
this.wrapS = gl.CLAMP_TO_EDGE;
this.wrapT = gl.CLAMP_TO_EDGE;
this.mipmap = false;
this.mipmapLinear = false;
}
//nPOT texture cannot mipmap
this.setFilter( this.linear, this.mipmap, this.mipmapLinear );
if (!this.options.depthTexture) {
this.renderbuffer = this.gl.createRenderbuffer();
this.gl.bindRenderbuffer(this.gl.RENDERBUFFER, this.renderbuffer);
this.gl.renderbufferStorage(this.gl.RENDERBUFFER, this.gl.DEPTH_COMPONENT16, this.width, this.height);
}
this.fbo = this.gl.createFramebuffer();
this.gl.bindFramebuffer( this.gl.FRAMEBUFFER, this.fbo );
this.gl.framebufferTexture2D(this.gl.FRAMEBUFFER, this.gl.COLOR_ATTACHMENT0, this.gl.TEXTURE_2D, this._texture, 0);
if (this.options.depthTexture) {
this.gl.framebufferTexture2D(this.gl.FRAMEBUFFER, this.gl.DEPTH_ATTACHMENT, this.gl.TEXTURE_2D, this.options.depthTexture._texture, 0);
}
else {
this.gl.framebufferRenderbuffer(this.gl.FRAMEBUFFER, this.gl.DEPTH_ATTACHMENT, this.gl.RENDERBUFFER, this.renderbuffer);
}
this.unbind();
}
/**
* [setFilter description]
* @param {[type]} linear [description]
* @param {[type]} mipmap [description]
* @param {[type]} mipmapLinear [description]
*/
setFilter(linear, mipmap, mipmapLinear) {
var gl = this.gl;
var filter = getFilter( !!linear, !!mipmap, !!mipmapLinear);
gl.bindTexture( gl.TEXTURE_2D, this._texture);
gl.texParameteri( gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, getFilter( !!linear, false, false ) );
gl.texParameteri( gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, filter );
}
resize(w, h) {
if( this.width !== w || this.height !== h ) {
this.width = w|0;
this.height = h|0;
}
var isPOT = isPowerOf2(this.width) && isPowerOf2(this.height);
if (!isPOT) {
this.wrapS = this.gl.CLAMP_TO_EDGE;
this.wrapT = this.gl.CLAMP_TO_EDGE;
this.mipmap = false;
this.mipmapLinear = false;
this.setFilter( this.linear, this.mipmap, this.mipmapLinear );
}
this.gl.bindTexture(this.gl.TEXTURE_2D, this._texture);
// this.gl.texImage2D(this.gl.TEXTURE_2D, 0, this.format, this.width, this.height, 0, this.format, this.type, new Uint8Array( new Array(this.width * this.height * 4) ));
if (this.type == this.gl.FLOAT) {
this.gl.texImage2D(this.gl.TEXTURE_2D, 0, this.format, this.width, this.height, 0, this.format, this.type, new Float32Array( new Array(this.width * this.height * 4) ));
}
else if (this.isHalfFloat) {
this.gl.texImage2D(this.gl.TEXTURE_2D, 0, this.format, this.width, this.height, 0, this.format, this.type, null);
}
else {
this.gl.texImage2D(this.gl.TEXTURE_2D, 0, this.format, this.width, this.height, 0, this.format, this.type, new Uint8Array( new Array(this.width * this.height * 4) ));
}
if (this.options.depthTexture) {
this.depthTexture.resize(this.width, this.height);
// this.gl.bindTexture(this.gl.TEXTURE_2D, this._depthTexture);
// this.gl.texImage2D(this.gl.TEXTURE_2D, 0, this.gl.DEPTH_COMPONENT, this.width, this.height, 0, this.gl.DEPTH_COMPONENT, this.gl.UNSIGNED_SHORT, null);
}
this.gl.bindFramebuffer( this.gl.FRAMEBUFFER, this.fbo );
this.gl.framebufferTexture2D(this.gl.FRAMEBUFFER, this.gl.COLOR_ATTACHMENT0, this.gl.TEXTURE_2D, this._texture, 0);
if (this.options.depthTexture) {
this.gl.framebufferTexture2D(this.gl.FRAMEBUFFER, this.gl.DEPTH_ATTACHMENT, this.gl.TEXTURE_2D, this.options.depthTexture._texture, 0);
}
else {
this.gl.bindRenderbuffer(this.gl.RENDERBUFFER, this.renderbuffer);
this.gl.renderbufferStorage(this.gl.RENDERBUFFER, this.gl.DEPTH_COMPONENT16, this.width, this.height);
this.gl.framebufferRenderbuffer(this.gl.FRAMEBUFFER, this.gl.DEPTH_ATTACHMENT, this.gl.RENDERBUFFER, this.renderbuffer);
}
this.unbind();
}
bindFrame() {
this.gl.viewport( 0, 0, this.width, this.height );
this.gl.bindFramebuffer(this.gl.FRAMEBUFFER, this.fbo);
if (!this.options.depthTexture) {
this.gl.bindRenderbuffer(this.gl.RENDERBUFFER, this.renderbuffer);
}
else {
this.gl.bindRenderbuffer(this.gl.RENDERBUFFER, this.renderbuffer);
this.gl.renderbufferStorage(this.gl.RENDERBUFFER, this.gl.DEPTH_COMPONENT16, this.width, this.height);
this.gl.framebufferRenderbuffer(this.gl.FRAMEBUFFER, this.gl.DEPTH_ATTACHMENT, this.gl.RENDERBUFFER, this.renderbuffer);
}
this.clear();
}
bind(unit) {
if (unit !== void 0) {
this.gl.activeTexture( this.gl.TEXTURE0 + (0|unit) );
}
// else {
// this.gl.activeTexture( this.gl.TEXTURE0 );
// }
this.gl.bindTexture(this.gl.TEXTURE_2D, this._texture);
}
unbind() {
this.gl.bindTexture(this.gl.TEXTURE_2D, null);
this.gl.bindFramebuffer(this.gl.FRAMEBUFFER, null);
if (!this.options.depthTexture) {
this.gl.bindRenderbuffer(this.gl.RENDERBUFFER, null);
}
}
clear(color, depth, stencil) {
var bits = 0;
if ( color === void 0 || color ) bits |= this.gl.COLOR_BUFFER_BIT;
if ( depth === void 0 || depth ) bits |= this.gl.DEPTH_BUFFER_BIT;
if ( stencil === void 0 || stencil ) bits |= this.gl.STENCIL_BUFFER_BIT;
this.gl.clear( bits );
}
dispose() {
this.gl.deleteFramebuffer( this.fbo );
this.fbo = null;
this.gl = null;
}
}
export default FrameBuffer;

View File

@@ -0,0 +1,74 @@
import Texture from './Texture';
class FrameBuffer extends Texture {
constructor ( gl, options ) {
super(gl, options);
this.fbo = this.gl.createFramebuffer();
this.renderbuffer = this.gl.createRenderbuffer();
this.gl.bindFramebuffer( this.gl.FRAMEBUFFER, this.fbo );
this.gl.framebufferTexture2D(this.gl.FRAMEBUFFER, this.gl.COLOR_ATTACHMENT0, this.gl.TEXTURE_2D, this._texture, 0);
this.gl.bindRenderbuffer(this.gl.RENDERBUFFER, this.renderbuffer);
this.gl.renderbufferStorage(this.gl.RENDERBUFFER, this.gl.DEPTH_COMPONENT16, this.width, this.height);
this.gl.framebufferRenderbuffer(this.gl.FRAMEBUFFER, this.gl.DEPTH_ATTACHMENT, this.gl.RENDERBUFFER, this.renderbuffer);
this.unbind();
}
resize( w, h ){
if( this.width !== w || this.height !== h ) {
this.width = w|0;
this.height = h|0;
}
this.gl.bindTexture(this.gl.TEXTURE_2D, this._texture);
this.gl.texImage2D(this.gl.TEXTURE_2D, 0, this.format, this.width, this.height, 0, this.format, this.type, null);
// this.gl.framebufferTexture2D( this.gl.FRAMEBUFFER, this.gl.COLOR_ATTACHMENT0, this.gl.TEXTURE_2D, this._texture, 0 );
this.gl.bindFramebuffer( this.gl.FRAMEBUFFER, this.fbo );
this.gl.framebufferTexture2D(this.gl.FRAMEBUFFER, this.gl.COLOR_ATTACHMENT0, this.gl.TEXTURE_2D, this._texture, 0);
this.gl.bindRenderbuffer(this.gl.RENDERBUFFER, this.renderbuffer);
this.gl.renderbufferStorage(this.gl.RENDERBUFFER, this.gl.DEPTH_COMPONENT16, this.width, this.height);
this.gl.framebufferRenderbuffer(this.gl.FRAMEBUFFER, this.gl.DEPTH_ATTACHMENT, this.gl.RENDERBUFFER, this.renderbuffer);
this.unbind();
}
bindFrame() {
this.gl.viewport( 0, 0, this.width, this.height );
this.gl.bindRenderbuffer(this.gl.RENDERBUFFER, this.renderbuffer);
this.gl.bindFramebuffer(this.gl.FRAMEBUFFER, this.fbo);
this.clear();
}
unbind() {
this.gl.bindTexture(this.gl.TEXTURE_2D, null);
this.gl.bindRenderbuffer(this.gl.RENDERBUFFER, null);
this.gl.bindFramebuffer(this.gl.FRAMEBUFFER, null);
}
clear(color, depth, stencil) {
var bits = 0;
if ( color === void 0 || color ) bits |= this.gl.COLOR_BUFFER_BIT;
if ( depth === void 0 || depth ) bits |= this.gl.DEPTH_BUFFER_BIT;
if ( stencil === void 0 || stencil ) bits |= this.gl.STENCIL_BUFFER_BIT;
this.gl.clear( bits );
}
dispose() {
this.gl.deleteFramebuffer( this.fbo );
this.fbo = null;
this.gl = null;
}
}
export default FrameBuffer;

View File

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

207
src/globe/beam/HDRTexture.js Executable file
View File

@@ -0,0 +1,207 @@
import uuid from './utils/uuid';
import isPowerOf2 from './utils/isPowerOf2';
import RGBEParser from './RGBEParser';
import parseHDR from 'parse-hdr';
function toArrayBuffer (buffer) {
var ab = new ArrayBuffer(buffer.length)
var view = new Uint8Array(ab)
for (var i = 0; i < buffer.length; ++i) {
view[i] = buffer[i]
}
return ab
}
function BinaryLoad(){
// this is just a helper class to ease BinaryLoad calls
var _this = this;
this.xmlhttp = new XMLHttpRequest();
this.get = function(url, callback){
_this.xmlhttp.onreadystatechange = function(){
if(_this.xmlhttp.readyState === 4){
callback(_this.xmlhttp.response, _this.xmlhttp.status);
}
};
_this.xmlhttp.open('GET', url, true);
_this.xmlhttp.responseType = 'arraybuffer'
_this.xmlhttp.send();
}
};
function RGBEByteToRGBFloat( sourceArray, sourceOffset, destArray, destOffset ) {
var e = sourceArray[ sourceOffset + 3 ];
var scale = Math.pow( 2.0, e - 128.0 ) / 255.0;
destArray[ destOffset + 0 ] = sourceArray[ sourceOffset + 0 ] * scale;
destArray[ destOffset + 1 ] = sourceArray[ sourceOffset + 1 ] * scale;
destArray[ destOffset + 2 ] = sourceArray[ sourceOffset + 2 ] * scale;
};
var RGBEByteToRGBHalf = ( function () {
// Source: http://gamedev.stackexchange.com/questions/17326/conversion-of-a-number-from-single-precision-floating-point-representation-to-a/17410#17410
var floatView = new Float32Array( 1 );
var int32View = new Int32Array( floatView.buffer );
/* This method is faster than the OpenEXR implementation (very often
* used, eg. in Ogre), with the additional benefit of rounding, inspired
* by James Tursa?s half-precision code. */
function toHalf( val ) {
floatView[ 0 ] = val;
var x = int32View[ 0 ];
var bits = ( x >> 16 ) & 0x8000; /* Get the sign */
var m = ( x >> 12 ) & 0x07ff; /* Keep one extra bit for rounding */
var e = ( x >> 23 ) & 0xff; /* Using int is faster here */
/* If zero, or denormal, or exponent underflows too much for a denormal
* half, return signed zero. */
if ( e < 103 ) return bits;
/* If NaN, return NaN. If Inf or exponent overflow, return Inf. */
if ( e > 142 ) {
bits |= 0x7c00;
/* If exponent was 0xff and one mantissa bit was set, it means NaN,
* not Inf, so make sure we set one mantissa bit too. */
bits |= ( ( e == 255 ) ? 0 : 1 ) && ( x & 0x007fffff );
return bits;
}
/* If exponent underflows but not too much, return a denormal */
if ( e < 113 ) {
m |= 0x0800;
/* Extra rounding may overflow and set mantissa to 0 and exponent
* to 1, which is OK. */
bits |= ( m >> ( 114 - e ) ) + ( ( m >> ( 113 - e ) ) & 1 );
return bits;
}
bits |= ( ( e - 112 ) << 10 ) | ( m >> 1 );
/* Extra rounding. An overflow will set mantissa to 0 and increment
* the exponent, which is OK. */
bits += m & 1;
return bits;
}
return function ( sourceArray, sourceOffset, destArray, destOffset ) {
var e = sourceArray[ sourceOffset + 3 ];
var scale = Math.pow( 2.0, e - 128.0 ) / 255.0;
destArray[ destOffset + 0 ] = toHalf( sourceArray[ sourceOffset + 0 ] * scale );
destArray[ destOffset + 1 ] = toHalf( sourceArray[ sourceOffset + 1 ] * scale );
destArray[ destOffset + 2 ] = toHalf( sourceArray[ sourceOffset + 2 ] * scale );
};
})();
class HDRTexture {
constructor(gl, options) {
options = Object.assign({}, {
format: gl.RGBA,
type: gl.UNSIGNED_BYTE,
width: 1,
height: 1,
linear: false,
mipmap: false,
miplinear: false,
wrapS: gl.CLAMP_TO_EDGE,
wrapT: gl.CLAMP_TO_EDGE,
url: null,
onReady:()=>{}
}, options);
this.options = options
this._uid = uuid();//debug purpose
this.gl = gl;
this.width = options.width;
this.height = options.height;
this.format = options.format;
this.type = options.type;
var floatTextures = gl.getExtension('OES_texture_float');
var floatTextureLinearFiltering = gl.getExtension('OES_texture_float_linear');
if (!floatTextures) {
throw('trying to create a FrameBuffer of with gl.FLOAT type but there\s no floating point texture support');
return;
}
this._texture = this.gl.createTexture();
gl.bindTexture( gl.TEXTURE_2D, this._texture);
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE);
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE);
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.NEAREST);
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.NEAREST);
gl.texImage2D(gl.TEXTURE_2D, 0, this.options.format, this.width, this.height, 0, this.options.format, this.gl.UNSIGNED_BYTE, new Uint8Array([0, 0, 0, 255]));
gl.bindTexture( gl.TEXTURE_2D, null);
if (this.options.url) {
this.load(this.options.url)
}
}
load(url) {
console.log("HDRTexture.load", url)
new BinaryLoad().get(url, (data, status)=>{
if (status === 200) {
// var arrBuffer = toArrayBuffer(data);
var texData = RGBEParser(data);
// if ( this.options.type === this.gl.FLOAT ) {
// var numElements = ( texData.data.length / 4 ) * 3;
// var floatdata = new Float32Array( numElements );
// for ( var j = 0; j < numElements; j ++ ) {
// RGBEByteToRGBFloat( texData.data, j * 4, floatdata, j * 3 );
// }
// texData.data = floatdata;
// } else if ( this.options.type === this.gl.HALF_FLOAT ) {
// var numElements = ( texData.data.length / 4 ) * 3;
// var halfdata = new Uint16Array( numElements );
// for ( var j = 0; j < numElements; j ++ ) {
// RGBEByteToRGBHalf( texData.data, j * 4, halfdata, j * 3 );
// }
// texData.data = halfdata;
// }
this.gl.bindTexture( this.gl.TEXTURE_2D, this._texture);
this.gl.texParameteri(this.gl.TEXTURE_2D, this.gl.TEXTURE_WRAP_S, this.gl.CLAMP_TO_EDGE);
this.gl.texParameteri(this.gl.TEXTURE_2D, this.gl.TEXTURE_WRAP_T, this.gl.CLAMP_TO_EDGE);
this.gl.texParameteri(this.gl.TEXTURE_2D, this.gl.TEXTURE_MIN_FILTER, this.gl.NEAREST);
this.gl.texParameteri(this.gl.TEXTURE_2D, this.gl.TEXTURE_MAG_FILTER, this.gl.NEAREST);
this.width = texData.width
this.height = texData.height
this.gl.texImage2D(this.gl.TEXTURE_2D, 0, this.options.format, texData.width, texData.height, 0, this.options.format, this.options.type, texData.data);
this.gl.bindTexture( this.gl.TEXTURE_2D, null);
this.options.onReady()
}
else {
error = true;
console.error('An error has occurred and the HDR "' + url + '" could not be downloaded.');
}
})
}
bind(unit) {
if (!this.gl) {
return;
}
//unit is sent by the Program and defined by the unfirom order in the shaders;
if (unit !== void 0) {
this.gl.activeTexture( this.gl.TEXTURE0 + (0|unit) );
}
this.gl.bindTexture(this.gl.TEXTURE_2D, this._texture);
}
delete() {
if (this.gl) {
this.gl.deleteTexture( this._texture );
}
this._texture = null;
this.gl = null;
}
}
export default HDRTexture;

View File

@@ -0,0 +1,84 @@
import {GeometryBuffer} from 'beam';
import {ArrayBuffer} from 'beam';
class Ajax {
constructor() {
this.xmlhttp = new XMLHttpRequest();
this.get = (url, callback)=>{
this.xmlhttp.onreadystatechange = ()=>{
if(this.xmlhttp.readyState === 4){
callback(this.xmlhttp.responseText, this.xmlhttp.status);
}
};
this.xmlhttp.open('GET', url, true);
this.xmlhttp.send();
}
}
};
class JSONGeometryBuffer extends GeometryBuffer {
constructor(gl, options) {
super(gl, 4.);
this.gl = gl;
options = Object.assign({},{
src: null,
onLoaded: ()=>{}
}, options);
this.options = options;
// buffers
this.indices = [];
this.vertices = [];
this.normals = [];
this.uvs = [];
// build geometry
this.length = 0;
this.addAttribute( 'index', new Uint16Array( this.indices ), 1 );
this.addAttribute( 'position', new Float32Array( this.vertices ), 3 );
this.addAttribute( 'normal', new Float32Array( this.normals ), 3 );
this.addAttribute( 'uv', new Float32Array( this.uvs ), 2 );
new Ajax().get(options.src, (data, status)=>{
if (status !== 200) {
console.error('An error has occurred while download JSON: ' + this.props.src);
throw '';
}
else {
this._onDataLoaded(JSON.parse(data))
}
});
}
_onDataLoaded(meshes) {
this.attributes = {}
this.indices = meshes.indices
this.vertices = meshes.vertices
this.normals = meshes.vertexNormals
this.uvs = meshes.textures
let needsUvs, needsNormals;
if (this.uvs.length == 0) {
needsUvs = true;
}
if (this.normals.length == 0) {
needsNormals = true;
}
for (let i=0; i<this.vertices.length/3;i++) {
if (needsUvs) {
this.uvs.push( 0,0 )
}
if (needsNormals) {
this.normals.push( 0,1,0 );
}
}
this.attributes['index'] = new ArrayBuffer(this.gl, new Uint16Array(this.indices), 1, true);
this.attributes['position'] = new ArrayBuffer(this.gl, new Float32Array(this.vertices), 3, false);
this.attributes['normal'] = new ArrayBuffer(this.gl, new Float32Array(this.normals), 3, false);
this.attributes['uv'] = new ArrayBuffer(this.gl, new Float32Array(this.uvs), 2, false);
// this.computeBoundingSphere();
this.options.onLoaded()
}
}
export default JSONGeometryBuffer;

98
src/globe/beam/Light.js Executable file
View File

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

33
src/globe/beam/Loader.js Executable file
View File

@@ -0,0 +1,33 @@
export default {
cache: {
},
loadImage (url, callback) {
if (this.cache[url] !== void 0) {
callback( this.cache[url] );
return;
}
var image = new Image();
image.onload = ()=>{
image.onload = null;
image.onerror = null;
this.cache[url] = image;
callback(image);
}
image.onerror = ()=>{
image.onload = null;
image.onerror = null;
console.warn('Cannot load image :' + url);
}
image.src = url;
}
}

54
src/globe/beam/Material.js Executable file
View File

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

90
src/globe/beam/Mesh.js Executable file
View File

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

View File

@@ -0,0 +1,68 @@
import {GeometryBuffer} from 'beam';
import {vec3} from 'beam';
import OBJ from "./webgl-obj-loader"
import {ArrayBuffer} from 'beam';
class ObjGeometryBuffer extends GeometryBuffer {
constructor(gl, options) {
super(gl, 4.);
this.gl = gl;
options = Object.assign({},{
src: null,
onLoaded: ()=>{}
}, options);
this.options = options;
// buffers
this.indices = [];
this.vertices = [];
this.normals = [];
this.uvs = [];
// build geometry
this.length = 0;
this.addAttribute( 'index', new Uint16Array( this.indices ), 1 );
this.addAttribute( 'position', new Float32Array( this.vertices ), 3 );
this.addAttribute( 'normal', new Float32Array( this.normals ), 3 );
this.addAttribute( 'uv', new Float32Array( this.uvs ), 2 );
this.onObjLoaded = this.onObjLoaded.bind(this);
if (options.lod) {
OBJ.downloadMeshes(options.lod, this.onObjLoaded)
}
else {
OBJ.downloadMeshes([options.src], this.onObjLoaded);
}
}
onObjLoaded(meshes) {
this.attributes = {}
this.indices = meshes[0].indices
this.vertices = meshes[0].vertices
this.normals = meshes[0].vertexNormals
this.uvs = meshes[0].textures
let needsUvs, needsNormals;
if (this.uvs.length == 0) {
needsUvs = true;
}
if (this.normals.length == 0) {
needsNormals = true;
}
for (let i=0; i<this.vertices.length/3;i++) {
if (needsUvs) {
this.uvs.push( 0,0 )
}
if (needsNormals) {
this.normals.push( 0,1,0 );
}
}
this.attributes['index'] = new ArrayBuffer(this.gl, new Uint16Array(this.indices), 1, true);
this.attributes['position'] = new ArrayBuffer(this.gl, new Float32Array(this.vertices), 3, false);
this.attributes['normal'] = new ArrayBuffer(this.gl, new Float32Array(this.normals), 3, false);
this.attributes['uv'] = new ArrayBuffer(this.gl, new Float32Array(this.uvs), 2, false);
// this.computeBoundingSphere();
this.options.onLoaded()
}
}
export default ObjGeometryBuffer;

170
src/globe/beam/Object3d.js Executable file
View File

@@ -0,0 +1,170 @@
import * as mat4 from './glMatrix/mat4';
import * as mat3 from './glMatrix/mat3';
import * as quat from './glMatrix/quat';
import * as vec3 from './glMatrix/vec3';
// var objects = []
// function needsUpdateLoop() {
// requestAnimationFrame(needsUpdateLoop);
// for (let i=0; i<objects.length; i++) {
// objects[i].needsUpdate = true;
// }
// }
// needsUpdateLoop();
class Object3d {
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;
}
//update once per frame
//TODO: use Raf
// if (needsUpdate) {
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
);
// var _rotMat4 = mat4.create();
// mat4.multiply(_rotMat4, _rotMat4, this._lookAtMat4);
// mat4.getRotation( this._quaternion, _rotMat4);
// mat4.identity(this._invLookatMat4);
mat4.invert(this.matrix, this.matrix);
// mat4.copy(this._rotationMat4, this._invLookatMat4);
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.matrix, this.parent.worldMatrix);
mat4.multiply(this.worldMatrix, this.parent.worldMatrix, this.matrix );
}
else{
this.worldMatrix = this.matrix;
}
mat4.invert(this.inverseWorldMatrix, this.worldMatrix);
}
}
export default Object3d;

117
src/globe/beam/ParticleSystem.js Executable file
View File

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

View File

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

448
src/globe/beam/Program.js Executable file
View File

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

View File

@@ -0,0 +1,331 @@
// adapted from http://www.graphics.cornell.edu/~bjw/rgbe.html
export default function parse( buffer ) {
var
/* return codes for rgbe routines */
RGBE_RETURN_SUCCESS = 0,
RGBE_RETURN_FAILURE = - 1,
/* default error routine. change this to change error handling */
rgbe_read_error = 1,
rgbe_write_error = 2,
rgbe_format_error = 3,
rgbe_memory_error = 4,
rgbe_error = function ( rgbe_error_code, msg ) {
switch ( rgbe_error_code ) {
case rgbe_read_error: console.error( "THREE.RGBELoader Read Error: " + ( msg || '' ) );
break;
case rgbe_write_error: console.error( "THREE.RGBELoader Write Error: " + ( msg || '' ) );
break;
case rgbe_format_error: console.error( "THREE.RGBELoader Bad File Format: " + ( msg || '' ) );
break;
default:
case rgbe_memory_error: console.error( "THREE.RGBELoader: Error: " + ( msg || '' ) );
}
return RGBE_RETURN_FAILURE;
},
/* offsets to red, green, and blue components in a data (float) pixel */
RGBE_DATA_RED = 0,
RGBE_DATA_GREEN = 1,
RGBE_DATA_BLUE = 2,
/* number of floats per pixel, use 4 since stored in rgba image format */
RGBE_DATA_SIZE = 4,
/* flags indicating which fields in an rgbe_header_info are valid */
RGBE_VALID_PROGRAMTYPE = 1,
RGBE_VALID_FORMAT = 2,
RGBE_VALID_DIMENSIONS = 4,
NEWLINE = "\n",
fgets = function ( buffer, lineLimit, consume ) {
lineLimit = ! lineLimit ? 1024 : lineLimit;
var p = buffer.pos,
i = - 1, len = 0, s = '', chunkSize = 128,
chunk = String.fromCharCode.apply( null, new Uint16Array( buffer.subarray( p, p + chunkSize ) ) )
;
while ( ( 0 > ( i = chunk.indexOf( NEWLINE ) ) ) && ( len < lineLimit ) && ( p < buffer.byteLength ) ) {
s += chunk; len += chunk.length;
p += chunkSize;
chunk += String.fromCharCode.apply( null, new Uint16Array( buffer.subarray( p, p + chunkSize ) ) );
}
if ( - 1 < i ) {
/*for (i=l-1; i>=0; i--) {
byteCode = m.charCodeAt(i);
if (byteCode > 0x7f && byteCode <= 0x7ff) byteLen++;
else if (byteCode > 0x7ff && byteCode <= 0xffff) byteLen += 2;
if (byteCode >= 0xDC00 && byteCode <= 0xDFFF) i--; //trail surrogate
}*/
if ( false !== consume ) buffer.pos += len + i + 1;
return s + chunk.slice( 0, i );
}
return false;
},
/* minimal header reading. modify if you want to parse more information */
RGBE_ReadHeader = function ( buffer ) {
var line, match,
// regexes to parse header info fields
magic_token_re = /^#\?(\S+)$/,
gamma_re = /^\s*GAMMA\s*=\s*(\d+(\.\d+)?)\s*$/,
exposure_re = /^\s*EXPOSURE\s*=\s*(\d+(\.\d+)?)\s*$/,
format_re = /^\s*FORMAT=(\S+)\s*$/,
dimensions_re = /^\s*\-Y\s+(\d+)\s+\+X\s+(\d+)\s*$/,
// RGBE format header struct
header = {
valid: 0, /* indicate which fields are valid */
string: '', /* the actual header string */
comments: '', /* comments found in header */
programtype: 'RGBE', /* listed at beginning of file to identify it after "#?". defaults to "RGBE" */
format: '', /* RGBE format, default 32-bit_rle_rgbe */
gamma: 1.0, /* image has already been gamma corrected with given gamma. defaults to 1.0 (no correction) */
exposure: 1.0, /* a value of 1.0 in an image corresponds to <exposure> watts/steradian/m^2. defaults to 1.0 */
width: 0, height: 0 /* image dimensions, width/height */
};
if ( buffer.pos >= buffer.byteLength || ! ( line = fgets( buffer ) ) ) {
return rgbe_error( rgbe_read_error, "no header found" );
}
/* if you want to require the magic token then uncomment the next line */
if ( ! ( match = line.match( magic_token_re ) ) ) {
return rgbe_error( rgbe_format_error, "bad initial token" );
}
header.valid |= RGBE_VALID_PROGRAMTYPE;
header.programtype = match[ 1 ];
header.string += line + "\n";
while ( true ) {
line = fgets( buffer );
if ( false === line ) break;
header.string += line + "\n";
if ( '#' === line.charAt( 0 ) ) {
header.comments += line + "\n";
continue; // comment line
}
if ( match = line.match( gamma_re ) ) {
header.gamma = parseFloat( match[ 1 ], 10 );
}
if ( match = line.match( exposure_re ) ) {
header.exposure = parseFloat( match[ 1 ], 10 );
}
if ( match = line.match( format_re ) ) {
header.valid |= RGBE_VALID_FORMAT;
header.format = match[ 1 ];//'32-bit_rle_rgbe';
}
if ( match = line.match( dimensions_re ) ) {
header.valid |= RGBE_VALID_DIMENSIONS;
header.height = parseInt( match[ 1 ], 10 );
header.width = parseInt( match[ 2 ], 10 );
}
if ( ( header.valid & RGBE_VALID_FORMAT ) && ( header.valid & RGBE_VALID_DIMENSIONS ) ) break;
}
if ( ! ( header.valid & RGBE_VALID_FORMAT ) ) {
return rgbe_error( rgbe_format_error, "missing format specifier" );
}
if ( ! ( header.valid & RGBE_VALID_DIMENSIONS ) ) {
return rgbe_error( rgbe_format_error, "missing image size specifier" );
}
return header;
},
RGBE_ReadPixels_RLE = function ( buffer, w, h ) {
var data_rgba, offset, pos, count, byteValue,
scanline_buffer, ptr, ptr_end, i, l, off, isEncodedRun,
scanline_width = w, num_scanlines = h, rgbeStart
;
if (
// run length encoding is not allowed so read flat
( ( scanline_width < 8 ) || ( scanline_width > 0x7fff ) ) ||
// this file is not run length encoded
( ( 2 !== buffer[ 0 ] ) || ( 2 !== buffer[ 1 ] ) || ( buffer[ 2 ] & 0x80 ) )
) {
// return the flat buffer
return new Uint8Array( buffer );
}
if ( scanline_width !== ( ( buffer[ 2 ] << 8 ) | buffer[ 3 ] ) ) {
return rgbe_error( rgbe_format_error, "wrong scanline width" );
}
data_rgba = new Uint8Array( 4 * w * h );
if ( ! data_rgba || ! data_rgba.length ) {
return rgbe_error( rgbe_memory_error, "unable to allocate buffer space" );
}
offset = 0; pos = 0; ptr_end = 4 * scanline_width;
rgbeStart = new Uint8Array( 4 );
scanline_buffer = new Uint8Array( ptr_end );
// read in each successive scanline
while ( ( num_scanlines > 0 ) && ( pos < buffer.byteLength ) ) {
if ( pos + 4 > buffer.byteLength ) {
return rgbe_error( rgbe_read_error );
}
rgbeStart[ 0 ] = buffer[ pos ++ ];
rgbeStart[ 1 ] = buffer[ pos ++ ];
rgbeStart[ 2 ] = buffer[ pos ++ ];
rgbeStart[ 3 ] = buffer[ pos ++ ];
if ( ( 2 != rgbeStart[ 0 ] ) || ( 2 != rgbeStart[ 1 ] ) || ( ( ( rgbeStart[ 2 ] << 8 ) | rgbeStart[ 3 ] ) != scanline_width ) ) {
return rgbe_error( rgbe_format_error, "bad rgbe scanline format" );
}
// read each of the four channels for the scanline into the buffer
// first red, then green, then blue, then exponent
ptr = 0;
while ( ( ptr < ptr_end ) && ( pos < buffer.byteLength ) ) {
count = buffer[ pos ++ ];
isEncodedRun = count > 128;
if ( isEncodedRun ) count -= 128;
if ( ( 0 === count ) || ( ptr + count > ptr_end ) ) {
return rgbe_error( rgbe_format_error, "bad scanline data" );
}
if ( isEncodedRun ) {
// a (encoded) run of the same value
byteValue = buffer[ pos ++ ];
for ( i = 0; i < count; i ++ ) {
scanline_buffer[ ptr ++ ] = byteValue;
}
//ptr += count;
} else {
// a literal-run
scanline_buffer.set( buffer.subarray( pos, pos + count ), ptr );
ptr += count; pos += count;
}
}
// now convert data from buffer into rgba
// first red, then green, then blue, then exponent (alpha)
l = scanline_width; //scanline_buffer.byteLength;
for ( i = 0; i < l; i ++ ) {
off = 0;
data_rgba[ offset ] = scanline_buffer[ i + off ];
off += scanline_width; //1;
data_rgba[ offset + 1 ] = scanline_buffer[ i + off ];
off += scanline_width; //1;
data_rgba[ offset + 2 ] = scanline_buffer[ i + off ];
off += scanline_width; //1;
data_rgba[ offset + 3 ] = scanline_buffer[ i + off ];
offset += 4;
}
num_scanlines --;
}
return data_rgba;
}
;
var byteArray = new Uint8Array( buffer ),
byteLength = byteArray.byteLength;
byteArray.pos = 0;
var rgbe_header_info = RGBE_ReadHeader( byteArray );
if ( RGBE_RETURN_FAILURE !== rgbe_header_info ) {
var w = rgbe_header_info.width,
h = rgbe_header_info.height,
image_rgba_data = RGBE_ReadPixels_RLE( byteArray.subarray( byteArray.pos ), w, h )
;
if ( RGBE_RETURN_FAILURE !== image_rgba_data ) {
return {
width: w,
height: h,
data: image_rgba_data,
header: rgbe_header_info.string,
gamma: rgbe_header_info.gamma,
exposure: rgbe_header_info.exposure,
format: 'RGBA', // handled as THREE.RGBAFormat in shaders
type: 'UnsignedByteType'
};
}
}
return null;
};

103
src/globe/beam/Renderer.js Executable file
View File

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

114
src/globe/beam/Scene.js Executable file
View File

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

View File

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

35
src/globe/beam/Sprite.js Executable file
View File

@@ -0,0 +1,35 @@
import Loader from './Loader';
import Mesh from './Mesh';
import Material from './Material';
import Texture from './Texture';
import PlaneGeometryBuffer from './PlaneGeometryBuffer';
class Sprite extends Mesh {
constructor(gl, url) {
super();
this.gl = gl;
Loader.loadImage(url, (image)=>{
this.texture = Texture.fromImage( this.gl, image );
this.material = new Material(this.gl, {
blend: true
});
this.material.map = this.texture;
this.geometry = new PlaneGeometryBuffer(this.gl, {
width: Math.floor(image.width/10),
height: Math.floor(image.height/10),
});
});
}
}
export default Sprite;

247
src/globe/beam/Texture.js Executable file
View File

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

View File

@@ -0,0 +1,32 @@
import GeometryBuffer from './GeometryBuffer';
class TriangleGeometryBuffer extends GeometryBuffer {
constructor(gl) {
super(gl, 3.);
this.addAttribute('position', new Float32Array([
-1.0, -1.0, 0.0,
0.0, 1.0, 0.0,
1.0, -1.0, 0.0
]), 3);
this.addAttribute('uv', new Float32Array([
0.0, 0.0,
0.5, 1.0,
1.0, 0.0,
]), 2, 'triangle');
this.addAttribute('color', new Float32Array([
1.0, 1.0, 1.0,
1.0, 1.0, 1.0,
1.0, 1.0, 1.0
]), 3);
}
}
export default TriangleGeometryBuffer;

View File

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

433
src/globe/beam/glMatrix/mat2.js Executable file
View File

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

466
src/globe/beam/glMatrix/mat2d.js Executable file
View File

@@ -0,0 +1,466 @@
/* Copyright (c) 2015, Brandon Jones, Colin MacKenzie IV.
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE. */
import * as glMatrix from "./common";
/**
* 2x3 Matrix
* @module mat2d
*
* @description
* A mat2d contains six elements defined as:
* <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;

765
src/globe/beam/glMatrix/mat3.js Executable file
View File

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

1681
src/globe/beam/glMatrix/mat4.js Executable file

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,68 @@
/* Copyright (c) 2013, Brandon Jones, Colin MacKenzie IV. All rights reserved.
Redistribution and use in source and binary forms, with or without modification,
are permitted provided that the following conditions are met:
* Redistributions of source code must retain the above copyright notice, this
list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */
const _GLMAT_EPSILON = 0.000001;
const _GLMAT_RANDOM = Math.random;
var _GLMAT_ARRAY_TYPE = (typeof Float32Array !== 'undefined') ? Float32Array : Array;
/**
* @class Common utilities
* @name glMatrix
*/
const _glMatrix = {};
/**
* Sets the type of array used when creating new vectors and matricies
*
* @param {Type} type Array type, such as Float32Array or Array
*/
_glMatrix.setMatrixArrayType = function(type) {
_GLMAT_ARRAY_TYPE = type;
}
var degree = Math.PI / 180;
/**
* Convert Degree To Radian
*
* @param {Number} Angle in Degrees
*/
_glMatrix.toRadian = function(a){
return a * degree;
}
export var GLMAT_ARRAY_TYPE = _GLMAT_ARRAY_TYPE;
export var GLMAT_EPSILON = _GLMAT_EPSILON;
export var GLMAT_RANDOM = _GLMAT_RANDOM;
export var glMatrix = _glMatrix;
// if(typeof(exports) !== 'undefined') {
// exports.GLMAT_ARRAY_TYPE = GLMAT_ARRAY_TYPE;
// exports.GLMAT_EPSILON = GLMAT_EPSILON;
// exports.GLMAT_RANDOM = GLMAT_RANDOM;
// exports.glMatrix = glMatrix;
// }

View File

@@ -0,0 +1,237 @@
import {GLMAT_ARRAY_TYPE} from "./common";
/* Copyright (c) 2013, Brandon Jones, Colin MacKenzie IV. All rights reserved.
Redistribution and use in source and binary forms, with or without modification,
are permitted provided that the following conditions are met:
* Redistributions of source code must retain the above copyright notice, this
list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */
/**
* @class 2x2 Matrix
* @name mat2
*/
var mat2 = {};
/**
* Creates a new identity mat2
*
* @returns {mat2} a new 2x2 matrix
*/
mat2.create = function() {
var out = new GLMAT_ARRAY_TYPE(4);
out[0] = 1;
out[1] = 0;
out[2] = 0;
out[3] = 1;
return out;
};
/**
* Creates a new mat2 initialized with values from an existing matrix
*
* @param {mat2} a matrix to clone
* @returns {mat2} a new 2x2 matrix
*/
mat2.clone = function(a) {
var out = new GLMAT_ARRAY_TYPE(4);
out[0] = a[0];
out[1] = a[1];
out[2] = a[2];
out[3] = a[3];
return out;
};
/**
* Copy the values from one mat2 to another
*
* @param {mat2} out the receiving matrix
* @param {mat2} a the source matrix
* @returns {mat2} out
*/
mat2.copy = function(out, a) {
out[0] = a[0];
out[1] = a[1];
out[2] = a[2];
out[3] = a[3];
return out;
};
/**
* Set a mat2 to the identity matrix
*
* @param {mat2} out the receiving matrix
* @returns {mat2} out
*/
mat2.identity = function(out) {
out[0] = 1;
out[1] = 0;
out[2] = 0;
out[3] = 1;
return out;
};
/**
* Transpose the values of a mat2
*
* @param {mat2} out the receiving matrix
* @param {mat2} a the source matrix
* @returns {mat2} out
*/
mat2.transpose = function(out, a) {
// If we are transposing ourselves we can skip a few steps but have to cache some values
if (out === a) {
var a1 = a[1];
out[1] = a[2];
out[2] = a1;
} else {
out[0] = a[0];
out[1] = a[2];
out[2] = a[1];
out[3] = a[3];
}
return out;
};
/**
* Inverts a mat2
*
* @param {mat2} out the receiving matrix
* @param {mat2} a the source matrix
* @returns {mat2} out
*/
mat2.invert = function(out, a) {
var a0 = a[0], a1 = a[1], a2 = a[2], a3 = a[3],
// Calculate the determinant
det = a0 * a3 - a2 * a1;
if (!det) {
return null;
}
det = 1.0 / det;
out[0] = a3 * det;
out[1] = -a1 * det;
out[2] = -a2 * det;
out[3] = a0 * det;
return out;
};
/**
* Calculates the adjugate of a mat2
*
* @param {mat2} out the receiving matrix
* @param {mat2} a the source matrix
* @returns {mat2} out
*/
mat2.adjoint = function(out, a) {
// Caching this value is nessecary if out == a
var a0 = a[0];
out[0] = a[3];
out[1] = -a[1];
out[2] = -a[2];
out[3] = a0;
return out;
};
/**
* Calculates the determinant of a mat2
*
* @param {mat2} a the source matrix
* @returns {Number} determinant of a
*/
mat2.determinant = function (a) {
return a[0] * a[3] - a[2] * a[1];
};
/**
* Multiplies two mat2's
*
* @param {mat2} out the receiving matrix
* @param {mat2} a the first operand
* @param {mat2} b the second operand
* @returns {mat2} out
*/
mat2.multiply = function (out, a, b) {
var a0 = a[0], a1 = a[1], a2 = a[2], a3 = a[3];
var b0 = b[0], b1 = b[1], b2 = b[2], b3 = b[3];
out[0] = a0 * b0 + a1 * b2;
out[1] = a0 * b1 + a1 * b3;
out[2] = a2 * b0 + a3 * b2;
out[3] = a2 * b1 + a3 * b3;
return out;
};
/**
* Alias for {@link mat2.multiply}
* @function
*/
mat2.mul = mat2.multiply;
/**
* Rotates a mat2 by the given angle
*
* @param {mat2} out the receiving matrix
* @param {mat2} a the matrix to rotate
* @param {Number} rad the angle to rotate the matrix by
* @returns {mat2} out
*/
mat2.rotate = function (out, a, rad) {
var a0 = a[0], a1 = a[1], a2 = a[2], a3 = a[3],
s = Math.sin(rad),
c = Math.cos(rad);
out[0] = a0 * c + a1 * s;
out[1] = a0 * -s + a1 * c;
out[2] = a2 * c + a3 * s;
out[3] = a2 * -s + a3 * c;
return out;
};
/**
* Scales the mat2 by the dimensions in the given vec2
*
* @param {mat2} out the receiving matrix
* @param {mat2} a the matrix to rotate
* @param {vec2} v the vec2 to scale the matrix by
* @returns {mat2} out
**/
mat2.scale = function(out, a, v) {
var a0 = a[0], a1 = a[1], a2 = a[2], a3 = a[3],
v0 = v[0], v1 = v[1];
out[0] = a0 * v0;
out[1] = a1 * v1;
out[2] = a2 * v0;
out[3] = a3 * v1;
return out;
};
/**
* Returns a string representation of a mat2
*
* @param {mat2} mat matrix to represent as a string
* @returns {String} string representation of the matrix
*/
mat2.str = function (a) {
return 'mat2(' + a[0] + ', ' + a[1] + ', ' + a[2] + ', ' + a[3] + ')';
};
export default mat2;

View File

@@ -0,0 +1,253 @@
import {GLMAT_ARRAY_TYPE} from "./common";
/* Copyright (c) 2013, Brandon Jones, Colin MacKenzie IV. All rights reserved.
Redistribution and use in source and binary forms, with or without modification,
are permitted provided that the following conditions are met:
* Redistributions of source code must retain the above copyright notice, this
list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */
/**
* @class 2x3 Matrix
* @name mat2d
*
* @description
* A mat2d contains six elements defined as:
* <pre>
* [a, b,
* c, d,
* tx,ty]
* </pre>
* This is a short form for the 3x3 matrix:
* <pre>
* [a, b, 0
* c, d, 0
* tx,ty,1]
* </pre>
* The last column is ignored so the array is shorter and operations are faster.
*/
var mat2d = {};
/**
* Creates a new identity mat2d
*
* @returns {mat2d} a new 2x3 matrix
*/
mat2d.create = function() {
var out = new GLMAT_ARRAY_TYPE(6);
out[0] = 1;
out[1] = 0;
out[2] = 0;
out[3] = 1;
out[4] = 0;
out[5] = 0;
return out;
};
/**
* Creates a new mat2d initialized with values from an existing matrix
*
* @param {mat2d} a matrix to clone
* @returns {mat2d} a new 2x3 matrix
*/
mat2d.clone = function(a) {
var out = new GLMAT_ARRAY_TYPE(6);
out[0] = a[0];
out[1] = a[1];
out[2] = a[2];
out[3] = a[3];
out[4] = a[4];
out[5] = a[5];
return out;
};
/**
* Copy the values from one mat2d to another
*
* @param {mat2d} out the receiving matrix
* @param {mat2d} a the source matrix
* @returns {mat2d} out
*/
mat2d.copy = function(out, a) {
out[0] = a[0];
out[1] = a[1];
out[2] = a[2];
out[3] = a[3];
out[4] = a[4];
out[5] = a[5];
return out;
};
/**
* Set a mat2d to the identity matrix
*
* @param {mat2d} out the receiving matrix
* @returns {mat2d} out
*/
mat2d.identity = function(out) {
out[0] = 1;
out[1] = 0;
out[2] = 0;
out[3] = 1;
out[4] = 0;
out[5] = 0;
return out;
};
/**
* Inverts a mat2d
*
* @param {mat2d} out the receiving matrix
* @param {mat2d} a the source matrix
* @returns {mat2d} out
*/
mat2d.invert = function(out, a) {
var aa = a[0], ab = a[1], ac = a[2], ad = a[3],
atx = a[4], aty = a[5];
var det = aa * ad - ab * ac;
if(!det){
return null;
}
det = 1.0 / det;
out[0] = ad * det;
out[1] = -ab * det;
out[2] = -ac * det;
out[3] = aa * det;
out[4] = (ac * aty - ad * atx) * det;
out[5] = (ab * atx - aa * aty) * det;
return out;
};
/**
* Calculates the determinant of a mat2d
*
* @param {mat2d} a the source matrix
* @returns {Number} determinant of a
*/
mat2d.determinant = function (a) {
return a[0] * a[3] - a[1] * a[2];
};
/**
* Multiplies two mat2d's
*
* @param {mat2d} out the receiving matrix
* @param {mat2d} a the first operand
* @param {mat2d} b the second operand
* @returns {mat2d} out
*/
mat2d.multiply = function (out, a, b) {
var aa = a[0], ab = a[1], ac = a[2], ad = a[3],
atx = a[4], aty = a[5],
ba = b[0], bb = b[1], bc = b[2], bd = b[3],
btx = b[4], bty = b[5];
out[0] = aa*ba + ab*bc;
out[1] = aa*bb + ab*bd;
out[2] = ac*ba + ad*bc;
out[3] = ac*bb + ad*bd;
out[4] = ba*atx + bc*aty + btx;
out[5] = bb*atx + bd*aty + bty;
return out;
};
/**
* Alias for {@link mat2d.multiply}
* @function
*/
mat2d.mul = mat2d.multiply;
/**
* Rotates a mat2d by the given angle
*
* @param {mat2d} out the receiving matrix
* @param {mat2d} a the matrix to rotate
* @param {Number} rad the angle to rotate the matrix by
* @returns {mat2d} out
*/
mat2d.rotate = function (out, a, rad) {
var aa = a[0],
ab = a[1],
ac = a[2],
ad = a[3],
atx = a[4],
aty = a[5],
st = Math.sin(rad),
ct = Math.cos(rad);
out[0] = aa*ct + ab*st;
out[1] = -aa*st + ab*ct;
out[2] = ac*ct + ad*st;
out[3] = -ac*st + ct*ad;
out[4] = ct*atx + st*aty;
out[5] = ct*aty - st*atx;
return out;
};
/**
* Scales the mat2d by the dimensions in the given vec2
*
* @param {mat2d} out the receiving matrix
* @param {mat2d} a the matrix to translate
* @param {vec2} v the vec2 to scale the matrix by
* @returns {mat2d} out
**/
mat2d.scale = function(out, a, v) {
var vx = v[0], vy = v[1];
out[0] = a[0] * vx;
out[1] = a[1] * vy;
out[2] = a[2] * vx;
out[3] = a[3] * vy;
out[4] = a[4] * vx;
out[5] = a[5] * vy;
return out;
};
/**
* Translates the mat2d by the dimensions in the given vec2
*
* @param {mat2d} out the receiving matrix
* @param {mat2d} a the matrix to translate
* @param {vec2} v the vec2 to translate the matrix by
* @returns {mat2d} out
**/
mat2d.translate = function(out, a, v) {
out[0] = a[0];
out[1] = a[1];
out[2] = a[2];
out[3] = a[3];
out[4] = a[4] + v[0];
out[5] = a[5] + v[1];
return out;
};
/**
* Returns a string representation of a mat2d
*
* @param {mat2d} a matrix to represent as a string
* @returns {String} string representation of the matrix
*/
mat2d.str = function (a) {
return 'mat2d(' + a[0] + ', ' + a[1] + ', ' + a[2] + ', ' +
a[3] + ', ' + a[4] + ', ' + a[5] + ')';
};
export default mat2d;

View File

@@ -0,0 +1,478 @@
import {GLMAT_ARRAY_TYPE} from "./common";
/* Copyright (c) 2013, Brandon Jones, Colin MacKenzie IV. All rights reserved.
Redistribution and use in source and binary forms, with or without modification,
are permitted provided that the following conditions are met:
* Redistributions of source code must retain the above copyright notice, this
list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */
/**
* @class 3x3 Matrix
* @name mat3
*/
var mat3 = {};
/**
* Creates a new identity mat3
*
* @returns {mat3} a new 3x3 matrix
*/
mat3.create = function() {
var out = new GLMAT_ARRAY_TYPE(9);
out[0] = 1;
out[1] = 0;
out[2] = 0;
out[3] = 0;
out[4] = 1;
out[5] = 0;
out[6] = 0;
out[7] = 0;
out[8] = 1;
return out;
};
/**
* Copies the upper-left 3x3 values into the given mat3.
*
* @param {mat3} out the receiving 3x3 matrix
* @param {mat4} a the source 4x4 matrix
* @returns {mat3} out
*/
mat3.fromMat4 = function(out, a) {
out[0] = a[0];
out[1] = a[1];
out[2] = a[2];
out[3] = a[4];
out[4] = a[5];
out[5] = a[6];
out[6] = a[8];
out[7] = a[9];
out[8] = a[10];
return out;
};
/**
* Creates a new mat3 initialized with values from an existing matrix
*
* @param {mat3} a matrix to clone
* @returns {mat3} a new 3x3 matrix
*/
mat3.clone = function(a) {
var out = new GLMAT_ARRAY_TYPE(9);
out[0] = a[0];
out[1] = a[1];
out[2] = a[2];
out[3] = a[3];
out[4] = a[4];
out[5] = a[5];
out[6] = a[6];
out[7] = a[7];
out[8] = a[8];
return out;
};
/**
* Copy the values from one mat3 to another
*
* @param {mat3} out the receiving matrix
* @param {mat3} a the source matrix
* @returns {mat3} out
*/
mat3.copy = function(out, a) {
out[0] = a[0];
out[1] = a[1];
out[2] = a[2];
out[3] = a[3];
out[4] = a[4];
out[5] = a[5];
out[6] = a[6];
out[7] = a[7];
out[8] = a[8];
return out;
};
/**
* Set a mat3 to the identity matrix
*
* @param {mat3} out the receiving matrix
* @returns {mat3} out
*/
mat3.identity = function(out) {
out[0] = 1;
out[1] = 0;
out[2] = 0;
out[3] = 0;
out[4] = 1;
out[5] = 0;
out[6] = 0;
out[7] = 0;
out[8] = 1;
return out;
};
/**
* Transpose the values of a mat3
*
* @param {mat3} out the receiving matrix
* @param {mat3} a the source matrix
* @returns {mat3} out
*/
mat3.transpose = function(out, a) {
// If we are transposing ourselves we can skip a few steps but have to cache some values
if (out === a) {
var a01 = a[1], a02 = a[2], a12 = a[5];
out[1] = a[3];
out[2] = a[6];
out[3] = a01;
out[5] = a[7];
out[6] = a02;
out[7] = a12;
} else {
out[0] = a[0];
out[1] = a[3];
out[2] = a[6];
out[3] = a[1];
out[4] = a[4];
out[5] = a[7];
out[6] = a[2];
out[7] = a[5];
out[8] = a[8];
}
return out;
};
/**
* Inverts a mat3
*
* @param {mat3} out the receiving matrix
* @param {mat3} a the source matrix
* @returns {mat3} out
*/
mat3.invert = function(out, a) {
var a00 = a[0], a01 = a[1], a02 = a[2],
a10 = a[3], a11 = a[4], a12 = a[5],
a20 = a[6], a21 = a[7], a22 = a[8],
b01 = a22 * a11 - a12 * a21,
b11 = -a22 * a10 + a12 * a20,
b21 = a21 * a10 - a11 * a20,
// Calculate the determinant
det = a00 * b01 + a01 * b11 + a02 * b21;
if (!det) {
return null;
}
det = 1.0 / det;
out[0] = b01 * det;
out[1] = (-a22 * a01 + a02 * a21) * det;
out[2] = (a12 * a01 - a02 * a11) * det;
out[3] = b11 * det;
out[4] = (a22 * a00 - a02 * a20) * det;
out[5] = (-a12 * a00 + a02 * a10) * det;
out[6] = b21 * det;
out[7] = (-a21 * a00 + a01 * a20) * det;
out[8] = (a11 * a00 - a01 * a10) * det;
return out;
};
/**
* Calculates the adjugate of a mat3
*
* @param {mat3} out the receiving matrix
* @param {mat3} a the source matrix
* @returns {mat3} out
*/
mat3.adjoint = function(out, a) {
var a00 = a[0], a01 = a[1], a02 = a[2],
a10 = a[3], a11 = a[4], a12 = a[5],
a20 = a[6], a21 = a[7], a22 = a[8];
out[0] = (a11 * a22 - a12 * a21);
out[1] = (a02 * a21 - a01 * a22);
out[2] = (a01 * a12 - a02 * a11);
out[3] = (a12 * a20 - a10 * a22);
out[4] = (a00 * a22 - a02 * a20);
out[5] = (a02 * a10 - a00 * a12);
out[6] = (a10 * a21 - a11 * a20);
out[7] = (a01 * a20 - a00 * a21);
out[8] = (a00 * a11 - a01 * a10);
return out;
};
/**
* Calculates the determinant of a mat3
*
* @param {mat3} a the source matrix
* @returns {Number} determinant of a
*/
mat3.determinant = function (a) {
var a00 = a[0], a01 = a[1], a02 = a[2],
a10 = a[3], a11 = a[4], a12 = a[5],
a20 = a[6], a21 = a[7], a22 = a[8];
return a00 * (a22 * a11 - a12 * a21) + a01 * (-a22 * a10 + a12 * a20) + a02 * (a21 * a10 - a11 * a20);
};
/**
* Multiplies two mat3's
*
* @param {mat3} out the receiving matrix
* @param {mat3} a the first operand
* @param {mat3} b the second operand
* @returns {mat3} out
*/
mat3.multiply = function (out, a, b) {
var a00 = a[0], a01 = a[1], a02 = a[2],
a10 = a[3], a11 = a[4], a12 = a[5],
a20 = a[6], a21 = a[7], a22 = a[8],
b00 = b[0], b01 = b[1], b02 = b[2],
b10 = b[3], b11 = b[4], b12 = b[5],
b20 = b[6], b21 = b[7], b22 = b[8];
out[0] = b00 * a00 + b01 * a10 + b02 * a20;
out[1] = b00 * a01 + b01 * a11 + b02 * a21;
out[2] = b00 * a02 + b01 * a12 + b02 * a22;
out[3] = b10 * a00 + b11 * a10 + b12 * a20;
out[4] = b10 * a01 + b11 * a11 + b12 * a21;
out[5] = b10 * a02 + b11 * a12 + b12 * a22;
out[6] = b20 * a00 + b21 * a10 + b22 * a20;
out[7] = b20 * a01 + b21 * a11 + b22 * a21;
out[8] = b20 * a02 + b21 * a12 + b22 * a22;
return out;
};
/**
* Alias for {@link mat3.multiply}
* @function
*/
mat3.mul = mat3.multiply;
/**
* Translate a mat3 by the given vector
*
* @param {mat3} out the receiving matrix
* @param {mat3} a the matrix to translate
* @param {vec2} v vector to translate by
* @returns {mat3} out
*/
mat3.translate = function(out, a, v) {
var a00 = a[0], a01 = a[1], a02 = a[2],
a10 = a[3], a11 = a[4], a12 = a[5],
a20 = a[6], a21 = a[7], a22 = a[8],
x = v[0], y = v[1];
out[0] = a00;
out[1] = a01;
out[2] = a02;
out[3] = a10;
out[4] = a11;
out[5] = a12;
out[6] = x * a00 + y * a10 + a20;
out[7] = x * a01 + y * a11 + a21;
out[8] = x * a02 + y * a12 + a22;
return out;
};
/**
* Rotates a mat3 by the given angle
*
* @param {mat3} out the receiving matrix
* @param {mat3} a the matrix to rotate
* @param {Number} rad the angle to rotate the matrix by
* @returns {mat3} out
*/
mat3.rotate = function (out, a, rad) {
var a00 = a[0], a01 = a[1], a02 = a[2],
a10 = a[3], a11 = a[4], a12 = a[5],
a20 = a[6], a21 = a[7], a22 = a[8],
s = Math.sin(rad),
c = Math.cos(rad);
out[0] = c * a00 + s * a10;
out[1] = c * a01 + s * a11;
out[2] = c * a02 + s * a12;
out[3] = c * a10 - s * a00;
out[4] = c * a11 - s * a01;
out[5] = c * a12 - s * a02;
out[6] = a20;
out[7] = a21;
out[8] = a22;
return out;
};
/**
* Scales the mat3 by the dimensions in the given vec2
*
* @param {mat3} out the receiving matrix
* @param {mat3} a the matrix to rotate
* @param {vec2} v the vec2 to scale the matrix by
* @returns {mat3} out
**/
mat3.scale = function(out, a, v) {
var x = v[0], y = v[1];
out[0] = x * a[0];
out[1] = x * a[1];
out[2] = x * a[2];
out[3] = y * a[3];
out[4] = y * a[4];
out[5] = y * a[5];
out[6] = a[6];
out[7] = a[7];
out[8] = a[8];
return out;
};
/**
* Copies the values from a mat2d into a mat3
*
* @param {mat3} out the receiving matrix
* @param {mat2d} a the matrix to copy
* @returns {mat3} out
**/
mat3.fromMat2d = function(out, a) {
out[0] = a[0];
out[1] = a[1];
out[2] = 0;
out[3] = a[2];
out[4] = a[3];
out[5] = 0;
out[6] = a[4];
out[7] = a[5];
out[8] = 1;
return out;
};
/**
* Calculates a 3x3 matrix from the given quaternion
*
* @param {mat3} out mat3 receiving operation result
* @param {quat} q Quaternion to create matrix from
*
* @returns {mat3} out
*/
mat3.fromQuat = function (out, q) {
var x = q[0], y = q[1], z = q[2], w = q[3],
x2 = x + x,
y2 = y + y,
z2 = z + z,
xx = x * x2,
xy = x * y2,
xz = x * z2,
yy = y * y2,
yz = y * z2,
zz = z * z2,
wx = w * x2,
wy = w * y2,
wz = w * z2;
out[0] = 1 - (yy + zz);
out[3] = xy + wz;
out[6] = xz - wy;
out[1] = xy - wz;
out[4] = 1 - (xx + zz);
out[7] = yz + wx;
out[2] = xz + wy;
out[5] = yz - wx;
out[8] = 1 - (xx + yy);
return out;
};
/**
* Calculates a 3x3 normal matrix (transpose inverse) from the 4x4 matrix
*
* @param {mat3} out mat3 receiving operation result
* @param {mat4} a Mat4 to derive the normal matrix from
*
* @returns {mat3} out
*/
mat3.normalFromMat4 = function (out, a) {
var a00 = a[0], a01 = a[1], a02 = a[2], a03 = a[3],
a10 = a[4], a11 = a[5], a12 = a[6], a13 = a[7],
a20 = a[8], a21 = a[9], a22 = a[10], a23 = a[11],
a30 = a[12], a31 = a[13], a32 = a[14], a33 = a[15],
b00 = a00 * a11 - a01 * a10,
b01 = a00 * a12 - a02 * a10,
b02 = a00 * a13 - a03 * a10,
b03 = a01 * a12 - a02 * a11,
b04 = a01 * a13 - a03 * a11,
b05 = a02 * a13 - a03 * a12,
b06 = a20 * a31 - a21 * a30,
b07 = a20 * a32 - a22 * a30,
b08 = a20 * a33 - a23 * a30,
b09 = a21 * a32 - a22 * a31,
b10 = a21 * a33 - a23 * a31,
b11 = a22 * a33 - a23 * a32,
// Calculate the determinant
det = b00 * b11 - b01 * b10 + b02 * b09 + b03 * b08 - b04 * b07 + b05 * b06;
if (!det) {
return null;
}
det = 1.0 / det;
out[0] = (a11 * b11 - a12 * b10 + a13 * b09) * det;
out[1] = (a12 * b08 - a10 * b11 - a13 * b07) * det;
out[2] = (a10 * b10 - a11 * b08 + a13 * b06) * det;
out[3] = (a02 * b10 - a01 * b11 - a03 * b09) * det;
out[4] = (a00 * b11 - a02 * b08 + a03 * b07) * det;
out[5] = (a01 * b08 - a00 * b10 - a03 * b06) * det;
out[6] = (a31 * b05 - a32 * b04 + a33 * b03) * det;
out[7] = (a32 * b02 - a30 * b05 - a33 * b01) * det;
out[8] = (a30 * b04 - a31 * b02 + a33 * b00) * det;
return out;
};
/**
* Returns a string representation of a mat3
*
* @param {mat3} mat matrix to represent as a string
* @returns {String} string representation of the matrix
*/
mat3.str = function (a) {
return 'mat3(' + a[0] + ', ' + a[1] + ', ' + a[2] + ', ' +
a[3] + ', ' + a[4] + ', ' + a[5] + ', ' +
a[6] + ', ' + a[7] + ', ' + a[8] + ')';
};
export default mat3;

View File

@@ -0,0 +1,908 @@
import {GLMAT_ARRAY_TYPE} from "./common";
import {GLMAT_EPSILON} from "./common";
/* Copyright (c) 2013, Brandon Jones, Colin MacKenzie IV. All rights reserved.
Redistribution and use in source and binary forms, with or without modification,
are permitted provided that the following conditions are met:
* Redistributions of source code must retain the above copyright notice, this
list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */
/**
* @class 4x4 Matrix
* @name mat4
*/
var mat4 = {};
/**
* Creates a new identity mat4
*
* @returns {mat4} a new 4x4 matrix
*/
mat4.create = function() {
var out = new GLMAT_ARRAY_TYPE(16);
out[0] = 1;
out[1] = 0;
out[2] = 0;
out[3] = 0;
out[4] = 0;
out[5] = 1;
out[6] = 0;
out[7] = 0;
out[8] = 0;
out[9] = 0;
out[10] = 1;
out[11] = 0;
out[12] = 0;
out[13] = 0;
out[14] = 0;
out[15] = 1;
return out;
};
/**
* Creates a new mat4 initialized with values from an existing matrix
*
* @param {mat4} a matrix to clone
* @returns {mat4} a new 4x4 matrix
*/
mat4.clone = function(a) {
var out = new GLMAT_ARRAY_TYPE(16);
out[0] = a[0];
out[1] = a[1];
out[2] = a[2];
out[3] = a[3];
out[4] = a[4];
out[5] = a[5];
out[6] = a[6];
out[7] = a[7];
out[8] = a[8];
out[9] = a[9];
out[10] = a[10];
out[11] = a[11];
out[12] = a[12];
out[13] = a[13];
out[14] = a[14];
out[15] = a[15];
return out;
};
/**
* Copy the values from one mat4 to another
*
* @param {mat4} out the receiving matrix
* @param {mat4} a the source matrix
* @returns {mat4} out
*/
mat4.copy = function(out, a) {
out[0] = a[0];
out[1] = a[1];
out[2] = a[2];
out[3] = a[3];
out[4] = a[4];
out[5] = a[5];
out[6] = a[6];
out[7] = a[7];
out[8] = a[8];
out[9] = a[9];
out[10] = a[10];
out[11] = a[11];
out[12] = a[12];
out[13] = a[13];
out[14] = a[14];
out[15] = a[15];
return out;
};
/**
* Set a mat4 to the identity matrix
*
* @param {mat4} out the receiving matrix
* @returns {mat4} out
*/
mat4.identity = function(out) {
out[0] = 1;
out[1] = 0;
out[2] = 0;
out[3] = 0;
out[4] = 0;
out[5] = 1;
out[6] = 0;
out[7] = 0;
out[8] = 0;
out[9] = 0;
out[10] = 1;
out[11] = 0;
out[12] = 0;
out[13] = 0;
out[14] = 0;
out[15] = 1;
return out;
};
/**
* Transpose the values of a mat4
*
* @param {mat4} out the receiving matrix
* @param {mat4} a the source matrix
* @returns {mat4} out
*/
mat4.transpose = function(out, a) {
// If we are transposing ourselves we can skip a few steps but have to cache some values
if (out === a) {
var a01 = a[1], a02 = a[2], a03 = a[3],
a12 = a[6], a13 = a[7],
a23 = a[11];
out[1] = a[4];
out[2] = a[8];
out[3] = a[12];
out[4] = a01;
out[6] = a[9];
out[7] = a[13];
out[8] = a02;
out[9] = a12;
out[11] = a[14];
out[12] = a03;
out[13] = a13;
out[14] = a23;
} else {
out[0] = a[0];
out[1] = a[4];
out[2] = a[8];
out[3] = a[12];
out[4] = a[1];
out[5] = a[5];
out[6] = a[9];
out[7] = a[13];
out[8] = a[2];
out[9] = a[6];
out[10] = a[10];
out[11] = a[14];
out[12] = a[3];
out[13] = a[7];
out[14] = a[11];
out[15] = a[15];
}
return out;
};
/**
* Inverts a mat4
*
* @param {mat4} out the receiving matrix
* @param {mat4} a the source matrix
* @returns {mat4} out
*/
mat4.invert = function(out, a) {
var a00 = a[0], a01 = a[1], a02 = a[2], a03 = a[3],
a10 = a[4], a11 = a[5], a12 = a[6], a13 = a[7],
a20 = a[8], a21 = a[9], a22 = a[10], a23 = a[11],
a30 = a[12], a31 = a[13], a32 = a[14], a33 = a[15],
b00 = a00 * a11 - a01 * a10,
b01 = a00 * a12 - a02 * a10,
b02 = a00 * a13 - a03 * a10,
b03 = a01 * a12 - a02 * a11,
b04 = a01 * a13 - a03 * a11,
b05 = a02 * a13 - a03 * a12,
b06 = a20 * a31 - a21 * a30,
b07 = a20 * a32 - a22 * a30,
b08 = a20 * a33 - a23 * a30,
b09 = a21 * a32 - a22 * a31,
b10 = a21 * a33 - a23 * a31,
b11 = a22 * a33 - a23 * a32,
// Calculate the determinant
det = b00 * b11 - b01 * b10 + b02 * b09 + b03 * b08 - b04 * b07 + b05 * b06;
if (!det) {
return null;
}
det = 1.0 / det;
out[0] = (a11 * b11 - a12 * b10 + a13 * b09) * det;
out[1] = (a02 * b10 - a01 * b11 - a03 * b09) * det;
out[2] = (a31 * b05 - a32 * b04 + a33 * b03) * det;
out[3] = (a22 * b04 - a21 * b05 - a23 * b03) * det;
out[4] = (a12 * b08 - a10 * b11 - a13 * b07) * det;
out[5] = (a00 * b11 - a02 * b08 + a03 * b07) * det;
out[6] = (a32 * b02 - a30 * b05 - a33 * b01) * det;
out[7] = (a20 * b05 - a22 * b02 + a23 * b01) * det;
out[8] = (a10 * b10 - a11 * b08 + a13 * b06) * det;
out[9] = (a01 * b08 - a00 * b10 - a03 * b06) * det;
out[10] = (a30 * b04 - a31 * b02 + a33 * b00) * det;
out[11] = (a21 * b02 - a20 * b04 - a23 * b00) * det;
out[12] = (a11 * b07 - a10 * b09 - a12 * b06) * det;
out[13] = (a00 * b09 - a01 * b07 + a02 * b06) * det;
out[14] = (a31 * b01 - a30 * b03 - a32 * b00) * det;
out[15] = (a20 * b03 - a21 * b01 + a22 * b00) * det;
return out;
};
/**
* Calculates the adjugate of a mat4
*
* @param {mat4} out the receiving matrix
* @param {mat4} a the source matrix
* @returns {mat4} out
*/
mat4.adjoint = function(out, a) {
var a00 = a[0], a01 = a[1], a02 = a[2], a03 = a[3],
a10 = a[4], a11 = a[5], a12 = a[6], a13 = a[7],
a20 = a[8], a21 = a[9], a22 = a[10], a23 = a[11],
a30 = a[12], a31 = a[13], a32 = a[14], a33 = a[15];
out[0] = (a11 * (a22 * a33 - a23 * a32) - a21 * (a12 * a33 - a13 * a32) + a31 * (a12 * a23 - a13 * a22));
out[1] = -(a01 * (a22 * a33 - a23 * a32) - a21 * (a02 * a33 - a03 * a32) + a31 * (a02 * a23 - a03 * a22));
out[2] = (a01 * (a12 * a33 - a13 * a32) - a11 * (a02 * a33 - a03 * a32) + a31 * (a02 * a13 - a03 * a12));
out[3] = -(a01 * (a12 * a23 - a13 * a22) - a11 * (a02 * a23 - a03 * a22) + a21 * (a02 * a13 - a03 * a12));
out[4] = -(a10 * (a22 * a33 - a23 * a32) - a20 * (a12 * a33 - a13 * a32) + a30 * (a12 * a23 - a13 * a22));
out[5] = (a00 * (a22 * a33 - a23 * a32) - a20 * (a02 * a33 - a03 * a32) + a30 * (a02 * a23 - a03 * a22));
out[6] = -(a00 * (a12 * a33 - a13 * a32) - a10 * (a02 * a33 - a03 * a32) + a30 * (a02 * a13 - a03 * a12));
out[7] = (a00 * (a12 * a23 - a13 * a22) - a10 * (a02 * a23 - a03 * a22) + a20 * (a02 * a13 - a03 * a12));
out[8] = (a10 * (a21 * a33 - a23 * a31) - a20 * (a11 * a33 - a13 * a31) + a30 * (a11 * a23 - a13 * a21));
out[9] = -(a00 * (a21 * a33 - a23 * a31) - a20 * (a01 * a33 - a03 * a31) + a30 * (a01 * a23 - a03 * a21));
out[10] = (a00 * (a11 * a33 - a13 * a31) - a10 * (a01 * a33 - a03 * a31) + a30 * (a01 * a13 - a03 * a11));
out[11] = -(a00 * (a11 * a23 - a13 * a21) - a10 * (a01 * a23 - a03 * a21) + a20 * (a01 * a13 - a03 * a11));
out[12] = -(a10 * (a21 * a32 - a22 * a31) - a20 * (a11 * a32 - a12 * a31) + a30 * (a11 * a22 - a12 * a21));
out[13] = (a00 * (a21 * a32 - a22 * a31) - a20 * (a01 * a32 - a02 * a31) + a30 * (a01 * a22 - a02 * a21));
out[14] = -(a00 * (a11 * a32 - a12 * a31) - a10 * (a01 * a32 - a02 * a31) + a30 * (a01 * a12 - a02 * a11));
out[15] = (a00 * (a11 * a22 - a12 * a21) - a10 * (a01 * a22 - a02 * a21) + a20 * (a01 * a12 - a02 * a11));
return out;
};
/**
* Calculates the determinant of a mat4
*
* @param {mat4} a the source matrix
* @returns {Number} determinant of a
*/
mat4.determinant = function (a) {
var a00 = a[0], a01 = a[1], a02 = a[2], a03 = a[3],
a10 = a[4], a11 = a[5], a12 = a[6], a13 = a[7],
a20 = a[8], a21 = a[9], a22 = a[10], a23 = a[11],
a30 = a[12], a31 = a[13], a32 = a[14], a33 = a[15],
b00 = a00 * a11 - a01 * a10,
b01 = a00 * a12 - a02 * a10,
b02 = a00 * a13 - a03 * a10,
b03 = a01 * a12 - a02 * a11,
b04 = a01 * a13 - a03 * a11,
b05 = a02 * a13 - a03 * a12,
b06 = a20 * a31 - a21 * a30,
b07 = a20 * a32 - a22 * a30,
b08 = a20 * a33 - a23 * a30,
b09 = a21 * a32 - a22 * a31,
b10 = a21 * a33 - a23 * a31,
b11 = a22 * a33 - a23 * a32;
// Calculate the determinant
return b00 * b11 - b01 * b10 + b02 * b09 + b03 * b08 - b04 * b07 + b05 * b06;
};
/**
* Multiplies two mat4's
*
* @param {mat4} out the receiving matrix
* @param {mat4} a the first operand
* @param {mat4} b the second operand
* @returns {mat4} out
*/
mat4.multiply = function (out, a, b) {
var a00 = a[0], a01 = a[1], a02 = a[2], a03 = a[3],
a10 = a[4], a11 = a[5], a12 = a[6], a13 = a[7],
a20 = a[8], a21 = a[9], a22 = a[10], a23 = a[11],
a30 = a[12], a31 = a[13], a32 = a[14], a33 = a[15];
// Cache only the current line of the second matrix
var b0 = b[0], b1 = b[1], b2 = b[2], b3 = b[3];
out[0] = b0*a00 + b1*a10 + b2*a20 + b3*a30;
out[1] = b0*a01 + b1*a11 + b2*a21 + b3*a31;
out[2] = b0*a02 + b1*a12 + b2*a22 + b3*a32;
out[3] = b0*a03 + b1*a13 + b2*a23 + b3*a33;
b0 = b[4]; b1 = b[5]; b2 = b[6]; b3 = b[7];
out[4] = b0*a00 + b1*a10 + b2*a20 + b3*a30;
out[5] = b0*a01 + b1*a11 + b2*a21 + b3*a31;
out[6] = b0*a02 + b1*a12 + b2*a22 + b3*a32;
out[7] = b0*a03 + b1*a13 + b2*a23 + b3*a33;
b0 = b[8]; b1 = b[9]; b2 = b[10]; b3 = b[11];
out[8] = b0*a00 + b1*a10 + b2*a20 + b3*a30;
out[9] = b0*a01 + b1*a11 + b2*a21 + b3*a31;
out[10] = b0*a02 + b1*a12 + b2*a22 + b3*a32;
out[11] = b0*a03 + b1*a13 + b2*a23 + b3*a33;
b0 = b[12]; b1 = b[13]; b2 = b[14]; b3 = b[15];
out[12] = b0*a00 + b1*a10 + b2*a20 + b3*a30;
out[13] = b0*a01 + b1*a11 + b2*a21 + b3*a31;
out[14] = b0*a02 + b1*a12 + b2*a22 + b3*a32;
out[15] = b0*a03 + b1*a13 + b2*a23 + b3*a33;
return out;
};
/**
* Alias for {@link mat4.multiply}
* @function
*/
mat4.mul = mat4.multiply;
/**
* Translate a mat4 by the given vector
*
* @param {mat4} out the receiving matrix
* @param {mat4} a the matrix to translate
* @param {vec3} v vector to translate by
* @returns {mat4} out
*/
mat4.translate = function (out, a, v) {
var x = v[0], y = v[1], z = v[2],
a00, a01, a02, a03,
a10, a11, a12, a13,
a20, a21, a22, a23;
if (a === out) {
out[12] = a[0] * x + a[4] * y + a[8] * z + a[12];
out[13] = a[1] * x + a[5] * y + a[9] * z + a[13];
out[14] = a[2] * x + a[6] * y + a[10] * z + a[14];
out[15] = a[3] * x + a[7] * y + a[11] * z + a[15];
} else {
a00 = a[0]; a01 = a[1]; a02 = a[2]; a03 = a[3];
a10 = a[4]; a11 = a[5]; a12 = a[6]; a13 = a[7];
a20 = a[8]; a21 = a[9]; a22 = a[10]; a23 = a[11];
out[0] = a00; out[1] = a01; out[2] = a02; out[3] = a03;
out[4] = a10; out[5] = a11; out[6] = a12; out[7] = a13;
out[8] = a20; out[9] = a21; out[10] = a22; out[11] = a23;
out[12] = a00 * x + a10 * y + a20 * z + a[12];
out[13] = a01 * x + a11 * y + a21 * z + a[13];
out[14] = a02 * x + a12 * y + a22 * z + a[14];
out[15] = a03 * x + a13 * y + a23 * z + a[15];
}
return out;
};
/**
* Scales the mat4 by the dimensions in the given vec3
*
* @param {mat4} out the receiving matrix
* @param {mat4} a the matrix to scale
* @param {vec3} v the vec3 to scale the matrix by
* @returns {mat4} out
**/
mat4.scale = function(out, a, v) {
var x = v[0], y = v[1], z = v[2];
out[0] = a[0] * x;
out[1] = a[1] * x;
out[2] = a[2] * x;
out[3] = a[3] * x;
out[4] = a[4] * y;
out[5] = a[5] * y;
out[6] = a[6] * y;
out[7] = a[7] * y;
out[8] = a[8] * z;
out[9] = a[9] * z;
out[10] = a[10] * z;
out[11] = a[11] * z;
out[12] = a[12];
out[13] = a[13];
out[14] = a[14];
out[15] = a[15];
return out;
};
/**
* Rotates a mat4 by the given angle
*
* @param {mat4} out the receiving matrix
* @param {mat4} a the matrix to rotate
* @param {Number} rad the angle to rotate the matrix by
* @param {vec3} axis the axis to rotate around
* @returns {mat4} out
*/
mat4.rotate = function (out, a, rad, axis) {
var x = axis[0], y = axis[1], z = axis[2],
len = Math.sqrt(x * x + y * y + z * z),
s, c, t,
a00, a01, a02, a03,
a10, a11, a12, a13,
a20, a21, a22, a23,
b00, b01, b02,
b10, b11, b12,
b20, b21, b22;
if (Math.abs(len) < GLMAT_EPSILON) { return null; }
len = 1 / len;
x *= len;
y *= len;
z *= len;
s = Math.sin(rad);
c = Math.cos(rad);
t = 1 - c;
a00 = a[0]; a01 = a[1]; a02 = a[2]; a03 = a[3];
a10 = a[4]; a11 = a[5]; a12 = a[6]; a13 = a[7];
a20 = a[8]; a21 = a[9]; a22 = a[10]; a23 = a[11];
// Construct the elements of the rotation matrix
b00 = x * x * t + c; b01 = y * x * t + z * s; b02 = z * x * t - y * s;
b10 = x * y * t - z * s; b11 = y * y * t + c; b12 = z * y * t + x * s;
b20 = x * z * t + y * s; b21 = y * z * t - x * s; b22 = z * z * t + c;
// Perform rotation-specific matrix multiplication
out[0] = a00 * b00 + a10 * b01 + a20 * b02;
out[1] = a01 * b00 + a11 * b01 + a21 * b02;
out[2] = a02 * b00 + a12 * b01 + a22 * b02;
out[3] = a03 * b00 + a13 * b01 + a23 * b02;
out[4] = a00 * b10 + a10 * b11 + a20 * b12;
out[5] = a01 * b10 + a11 * b11 + a21 * b12;
out[6] = a02 * b10 + a12 * b11 + a22 * b12;
out[7] = a03 * b10 + a13 * b11 + a23 * b12;
out[8] = a00 * b20 + a10 * b21 + a20 * b22;
out[9] = a01 * b20 + a11 * b21 + a21 * b22;
out[10] = a02 * b20 + a12 * b21 + a22 * b22;
out[11] = a03 * b20 + a13 * b21 + a23 * b22;
if (a !== out) { // If the source and destination differ, copy the unchanged last row
out[12] = a[12];
out[13] = a[13];
out[14] = a[14];
out[15] = a[15];
}
return out;
};
/**
* Rotates a matrix by the given angle around the X axis
*
* @param {mat4} out the receiving matrix
* @param {mat4} a the matrix to rotate
* @param {Number} rad the angle to rotate the matrix by
* @returns {mat4} out
*/
mat4.rotateX = function (out, a, rad) {
var s = Math.sin(rad),
c = Math.cos(rad),
a10 = a[4],
a11 = a[5],
a12 = a[6],
a13 = a[7],
a20 = a[8],
a21 = a[9],
a22 = a[10],
a23 = a[11];
if (a !== out) { // If the source and destination differ, copy the unchanged rows
out[0] = a[0];
out[1] = a[1];
out[2] = a[2];
out[3] = a[3];
out[12] = a[12];
out[13] = a[13];
out[14] = a[14];
out[15] = a[15];
}
// Perform axis-specific matrix multiplication
out[4] = a10 * c + a20 * s;
out[5] = a11 * c + a21 * s;
out[6] = a12 * c + a22 * s;
out[7] = a13 * c + a23 * s;
out[8] = a20 * c - a10 * s;
out[9] = a21 * c - a11 * s;
out[10] = a22 * c - a12 * s;
out[11] = a23 * c - a13 * s;
return out;
};
/**
* Rotates a matrix by the given angle around the Y axis
*
* @param {mat4} out the receiving matrix
* @param {mat4} a the matrix to rotate
* @param {Number} rad the angle to rotate the matrix by
* @returns {mat4} out
*/
mat4.rotateY = function (out, a, rad) {
var s = Math.sin(rad),
c = Math.cos(rad),
a00 = a[0],
a01 = a[1],
a02 = a[2],
a03 = a[3],
a20 = a[8],
a21 = a[9],
a22 = a[10],
a23 = a[11];
if (a !== out) { // If the source and destination differ, copy the unchanged rows
out[4] = a[4];
out[5] = a[5];
out[6] = a[6];
out[7] = a[7];
out[12] = a[12];
out[13] = a[13];
out[14] = a[14];
out[15] = a[15];
}
// Perform axis-specific matrix multiplication
out[0] = a00 * c - a20 * s;
out[1] = a01 * c - a21 * s;
out[2] = a02 * c - a22 * s;
out[3] = a03 * c - a23 * s;
out[8] = a00 * s + a20 * c;
out[9] = a01 * s + a21 * c;
out[10] = a02 * s + a22 * c;
out[11] = a03 * s + a23 * c;
return out;
};
/**
* Rotates a matrix by the given angle around the Z axis
*
* @param {mat4} out the receiving matrix
* @param {mat4} a the matrix to rotate
* @param {Number} rad the angle to rotate the matrix by
* @returns {mat4} out
*/
mat4.rotateZ = function (out, a, rad) {
var s = Math.sin(rad),
c = Math.cos(rad),
a00 = a[0],
a01 = a[1],
a02 = a[2],
a03 = a[3],
a10 = a[4],
a11 = a[5],
a12 = a[6],
a13 = a[7];
if (a !== out) { // If the source and destination differ, copy the unchanged last row
out[8] = a[8];
out[9] = a[9];
out[10] = a[10];
out[11] = a[11];
out[12] = a[12];
out[13] = a[13];
out[14] = a[14];
out[15] = a[15];
}
// Perform axis-specific matrix multiplication
out[0] = a00 * c + a10 * s;
out[1] = a01 * c + a11 * s;
out[2] = a02 * c + a12 * s;
out[3] = a03 * c + a13 * s;
out[4] = a10 * c - a00 * s;
out[5] = a11 * c - a01 * s;
out[6] = a12 * c - a02 * s;
out[7] = a13 * c - a03 * s;
return out;
};
/**
* Creates a matrix from a quaternion rotation and vector translation
* This is equivalent to (but much faster than):
*
* mat4.identity(dest);
* mat4.translate(dest, vec);
* var quatMat = mat4.create();
* quat4.toMat4(quat, quatMat);
* mat4.multiply(dest, quatMat);
*
* @param {mat4} out mat4 receiving operation result
* @param {quat4} q Rotation quaternion
* @param {vec3} v Translation vector
* @returns {mat4} out
*/
mat4.fromRotationTranslation = function (out, q, v) {
// Quaternion math
var x = q[0], y = q[1], z = q[2], w = q[3],
x2 = x + x,
y2 = y + y,
z2 = z + z,
xx = x * x2,
xy = x * y2,
xz = x * z2,
yy = y * y2,
yz = y * z2,
zz = z * z2,
wx = w * x2,
wy = w * y2,
wz = w * z2;
out[0] = 1 - (yy + zz);
out[1] = xy + wz;
out[2] = xz - wy;
out[3] = 0;
out[4] = xy - wz;
out[5] = 1 - (xx + zz);
out[6] = yz + wx;
out[7] = 0;
out[8] = xz + wy;
out[9] = yz - wx;
out[10] = 1 - (xx + yy);
out[11] = 0;
out[12] = v[0];
out[13] = v[1];
out[14] = v[2];
out[15] = 1;
return out;
};
/**
* Calculates a 4x4 matrix from the given quaternion
*
* @param {mat4} out mat4 receiving operation result
* @param {quat} q Quaternion to create matrix from
*
* @returns {mat4} out
*/
mat4.fromQuat = function (out, q) {
var x = q[0], y = q[1], z = q[2], w = q[3],
x2 = x + x,
y2 = y + y,
z2 = z + z,
xx = x * x2,
xy = x * y2,
xz = x * z2,
yy = y * y2,
yz = y * z2,
zz = z * z2,
wx = w * x2,
wy = w * y2,
wz = w * z2;
out[0] = 1 - (yy + zz);
out[1] = xy + wz;
out[2] = xz - wy;
out[3] = 0;
out[4] = xy - wz;
out[5] = 1 - (xx + zz);
out[6] = yz + wx;
out[7] = 0;
out[8] = xz + wy;
out[9] = yz - wx;
out[10] = 1 - (xx + yy);
out[11] = 0;
out[12] = 0;
out[13] = 0;
out[14] = 0;
out[15] = 1;
return out;
};
/**
* Generates a frustum matrix with the given bounds
*
* @param {mat4} out mat4 frustum matrix will be written into
* @param {Number} left Left bound of the frustum
* @param {Number} right Right bound of the frustum
* @param {Number} bottom Bottom bound of the frustum
* @param {Number} top Top bound of the frustum
* @param {Number} near Near bound of the frustum
* @param {Number} far Far bound of the frustum
* @returns {mat4} out
*/
mat4.frustum = function (out, left, right, bottom, top, near, far) {
var rl = 1 / (right - left),
tb = 1 / (top - bottom),
nf = 1 / (near - far);
out[0] = (near * 2) * rl;
out[1] = 0;
out[2] = 0;
out[3] = 0;
out[4] = 0;
out[5] = (near * 2) * tb;
out[6] = 0;
out[7] = 0;
out[8] = (right + left) * rl;
out[9] = (top + bottom) * tb;
out[10] = (far + near) * nf;
out[11] = -1;
out[12] = 0;
out[13] = 0;
out[14] = (far * near * 2) * nf;
out[15] = 0;
return out;
};
/**
* Generates a perspective projection matrix with the given bounds
*
* @param {mat4} out mat4 frustum matrix will be written into
* @param {number} fovy Vertical field of view in radians
* @param {number} aspect Aspect ratio. typically viewport width/height
* @param {number} near Near bound of the frustum
* @param {number} far Far bound of the frustum
* @returns {mat4} out
*/
mat4.perspective = function (out, fovy, aspect, near, far) {
var f = 1.0 / Math.tan(fovy / 2),
nf = 1 / (near - far);
out[0] = f / aspect;
out[1] = 0;
out[2] = 0;
out[3] = 0;
out[4] = 0;
out[5] = f;
out[6] = 0;
out[7] = 0;
out[8] = 0;
out[9] = 0;
out[10] = (far + near) * nf;
out[11] = -1;
out[12] = 0;
out[13] = 0;
out[14] = (2 * far * near) * nf;
out[15] = 0;
return out;
};
/**
* Generates a orthogonal projection matrix with the given bounds
*
* @param {mat4} out mat4 frustum matrix will be written into
* @param {number} left Left bound of the frustum
* @param {number} right Right bound of the frustum
* @param {number} bottom Bottom bound of the frustum
* @param {number} top Top bound of the frustum
* @param {number} near Near bound of the frustum
* @param {number} far Far bound of the frustum
* @returns {mat4} out
*/
mat4.ortho = function (out, left, right, bottom, top, near, far) {
var lr = 1 / (left - right),
bt = 1 / (bottom - top),
nf = 1 / (near - far);
out[0] = -2 * lr;
out[1] = 0;
out[2] = 0;
out[3] = 0;
out[4] = 0;
out[5] = -2 * bt;
out[6] = 0;
out[7] = 0;
out[8] = 0;
out[9] = 0;
out[10] = 2 * nf;
out[11] = 0;
out[12] = (left + right) * lr;
out[13] = (top + bottom) * bt;
out[14] = (far + near) * nf;
out[15] = 1;
return out;
};
/**
* Generates a look-at matrix with the given eye position, focal point, and up axis
*
* @param {mat4} out mat4 frustum matrix will be written into
* @param {vec3} eye Position of the viewer
* @param {vec3} center Point the viewer is looking at
* @param {vec3} up vec3 pointing up
* @returns {mat4} out
*/
mat4.lookAt = function (out, eye, center, up) {
var x0, x1, x2, y0, y1, y2, z0, z1, z2, len,
eyex = eye[0],
eyey = eye[1],
eyez = eye[2],
upx = up[0],
upy = up[1],
upz = up[2],
centerx = center[0],
centery = center[1],
centerz = center[2];
if (Math.abs(eyex - centerx) < GLMAT_EPSILON &&
Math.abs(eyey - centery) < GLMAT_EPSILON &&
Math.abs(eyez - centerz) < GLMAT_EPSILON) {
return mat4.identity(out);
}
z0 = eyex - centerx;
z1 = eyey - centery;
z2 = eyez - centerz;
len = 1 / Math.sqrt(z0 * z0 + z1 * z1 + z2 * z2);
z0 *= len;
z1 *= len;
z2 *= len;
x0 = upy * z2 - upz * z1;
x1 = upz * z0 - upx * z2;
x2 = upx * z1 - upy * z0;
len = Math.sqrt(x0 * x0 + x1 * x1 + x2 * x2);
if (!len) {
x0 = 0;
x1 = 0;
x2 = 0;
} else {
len = 1 / len;
x0 *= len;
x1 *= len;
x2 *= len;
}
y0 = z1 * x2 - z2 * x1;
y1 = z2 * x0 - z0 * x2;
y2 = z0 * x1 - z1 * x0;
len = Math.sqrt(y0 * y0 + y1 * y1 + y2 * y2);
if (!len) {
y0 = 0;
y1 = 0;
y2 = 0;
} else {
len = 1 / len;
y0 *= len;
y1 *= len;
y2 *= len;
}
out[0] = x0;
out[1] = y0;
out[2] = z0;
out[3] = 0;
out[4] = x1;
out[5] = y1;
out[6] = z1;
out[7] = 0;
out[8] = x2;
out[9] = y2;
out[10] = z2;
out[11] = 0;
out[12] = -(x0 * eyex + x1 * eyey + x2 * eyez);
out[13] = -(y0 * eyex + y1 * eyey + y2 * eyez);
out[14] = -(z0 * eyex + z1 * eyey + z2 * eyez);
out[15] = 1;
return out;
};
/**
* Returns a string representation of a mat4
*
* @param {mat4} mat matrix to represent as a string
* @returns {String} string representation of the matrix
*/
mat4.str = function (a) {
return 'mat4(' + a[0] + ', ' + a[1] + ', ' + a[2] + ', ' + a[3] + ', ' +
a[4] + ', ' + a[5] + ', ' + a[6] + ', ' + a[7] + ', ' +
a[8] + ', ' + a[9] + ', ' + a[10] + ', ' + a[11] + ', ' +
a[12] + ', ' + a[13] + ', ' + a[14] + ', ' + a[15] + ')';
};
export default mat4;

View File

@@ -0,0 +1,531 @@
import {GLMAT_ARRAY_TYPE} from "./common";
import vec3 from "./vec3";
import vec4 from "./vec4";
import mat3 from "./mat3";
/* Copyright (c) 2013, Brandon Jones, Colin MacKenzie IV. All rights reserved.
Redistribution and use in source and binary forms, with or without modification,
are permitted provided that the following conditions are met:
* Redistributions of source code must retain the above copyright notice, this
list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */
/**
* @class Quaternion
* @name quat
*/
var quat = {};
/**
* Creates a new identity quat
*
* @returns {quat} a new quaternion
*/
quat.create = function() {
var out = new GLMAT_ARRAY_TYPE(4);
out[0] = 0;
out[1] = 0;
out[2] = 0;
out[3] = 1;
return out;
};
/**
* Sets a quaternion to represent the shortest rotation from one
* vector to another.
*
* Both vectors are assumed to be unit length.
*
* @param {quat} out the receiving quaternion.
* @param {vec3} a the initial vector
* @param {vec3} b the destination vector
* @returns {quat} out
*/
quat.rotationTo = (function() {
var tmpvec3 = vec3.create();
var xUnitVec3 = vec3.fromValues(1,0,0);
var yUnitVec3 = vec3.fromValues(0,1,0);
return function(out, a, b) {
var dot = vec3.dot(a, b);
if (dot < -0.999999) {
vec3.cross(tmpvec3, xUnitVec3, a);
if (vec3.length(tmpvec3) < 0.000001)
vec3.cross(tmpvec3, yUnitVec3, a);
vec3.normalize(tmpvec3, tmpvec3);
quat.setAxisAngle(out, tmpvec3, Math.PI);
return out;
} else if (dot > 0.999999) {
out[0] = 0;
out[1] = 0;
out[2] = 0;
out[3] = 1;
return out;
} else {
vec3.cross(tmpvec3, a, b);
out[0] = tmpvec3[0];
out[1] = tmpvec3[1];
out[2] = tmpvec3[2];
out[3] = 1 + dot;
return quat.normalize(out, out);
}
};
})();
/**
* Sets the specified quaternion with values corresponding to the given
* axes. Each axis is a vec3 and is expected to be unit length and
* perpendicular to all other specified axes.
*
* @param {vec3} view the vector representing the viewing direction
* @param {vec3} right the vector representing the local "right" direction
* @param {vec3} up the vector representing the local "up" direction
* @returns {quat} out
*/
quat.setAxes = (function() {
var matr = mat3.create();
return function(out, view, right, up) {
matr[0] = right[0];
matr[3] = right[1];
matr[6] = right[2];
matr[1] = up[0];
matr[4] = up[1];
matr[7] = up[2];
matr[2] = view[0];
matr[5] = view[1];
matr[8] = view[2];
return quat.normalize(out, quat.fromMat3(out, matr));
};
})();
/**
* Creates a new quat initialized with values from an existing quaternion
*
* @param {quat} a quaternion to clone
* @returns {quat} a new quaternion
* @function
*/
quat.clone = vec4.clone;
/**
* Creates a new quat initialized with the given values
*
* @param {Number} x X component
* @param {Number} y Y component
* @param {Number} z Z component
* @param {Number} w W component
* @returns {quat} a new quaternion
* @function
*/
quat.fromValues = vec4.fromValues;
/**
* Copy the values from one quat to another
*
* @param {quat} out the receiving quaternion
* @param {quat} a the source quaternion
* @returns {quat} out
* @function
*/
quat.copy = vec4.copy;
/**
* Set the components of a quat to the given values
*
* @param {quat} out the receiving quaternion
* @param {Number} x X component
* @param {Number} y Y component
* @param {Number} z Z component
* @param {Number} w W component
* @returns {quat} out
* @function
*/
quat.set = vec4.set;
/**
* Set a quat to the identity quaternion
*
* @param {quat} out the receiving quaternion
* @returns {quat} out
*/
quat.identity = function(out) {
out[0] = 0;
out[1] = 0;
out[2] = 0;
out[3] = 1;
return out;
};
/**
* Sets a quat from the given angle and rotation axis,
* then returns it.
*
* @param {quat} out the receiving quaternion
* @param {vec3} axis the axis around which to rotate
* @param {Number} rad the angle in radians
* @returns {quat} out
**/
quat.setAxisAngle = function(out, axis, rad) {
rad = rad * 0.5;
var s = Math.sin(rad);
out[0] = s * axis[0];
out[1] = s * axis[1];
out[2] = s * axis[2];
out[3] = Math.cos(rad);
return out;
};
/**
* Adds two quat's
*
* @param {quat} out the receiving quaternion
* @param {quat} a the first operand
* @param {quat} b the second operand
* @returns {quat} out
* @function
*/
quat.add = vec4.add;
/**
* Multiplies two quat's
*
* @param {quat} out the receiving quaternion
* @param {quat} a the first operand
* @param {quat} b the second operand
* @returns {quat} out
*/
quat.multiply = function(out, a, b) {
var ax = a[0], ay = a[1], az = a[2], aw = a[3],
bx = b[0], by = b[1], bz = b[2], bw = b[3];
out[0] = ax * bw + aw * bx + ay * bz - az * by;
out[1] = ay * bw + aw * by + az * bx - ax * bz;
out[2] = az * bw + aw * bz + ax * by - ay * bx;
out[3] = aw * bw - ax * bx - ay * by - az * bz;
return out;
};
/**
* Alias for {@link quat.multiply}
* @function
*/
quat.mul = quat.multiply;
/**
* Scales a quat by a scalar number
*
* @param {quat} out the receiving vector
* @param {quat} a the vector to scale
* @param {Number} b amount to scale the vector by
* @returns {quat} out
* @function
*/
quat.scale = vec4.scale;
/**
* Rotates a quaternion by the given angle about the X axis
*
* @param {quat} out quat receiving operation result
* @param {quat} a quat to rotate
* @param {number} rad angle (in radians) to rotate
* @returns {quat} out
*/
quat.rotateX = function (out, a, rad) {
rad *= 0.5;
var ax = a[0], ay = a[1], az = a[2], aw = a[3],
bx = Math.sin(rad), bw = Math.cos(rad);
out[0] = ax * bw + aw * bx;
out[1] = ay * bw + az * bx;
out[2] = az * bw - ay * bx;
out[3] = aw * bw - ax * bx;
return out;
};
/**
* Rotates a quaternion by the given angle about the Y axis
*
* @param {quat} out quat receiving operation result
* @param {quat} a quat to rotate
* @param {number} rad angle (in radians) to rotate
* @returns {quat} out
*/
quat.rotateY = function (out, a, rad) {
rad *= 0.5;
var ax = a[0], ay = a[1], az = a[2], aw = a[3],
by = Math.sin(rad), bw = Math.cos(rad);
out[0] = ax * bw - az * by;
out[1] = ay * bw + aw * by;
out[2] = az * bw + ax * by;
out[3] = aw * bw - ay * by;
return out;
};
/**
* Rotates a quaternion by the given angle about the Z axis
*
* @param {quat} out quat receiving operation result
* @param {quat} a quat to rotate
* @param {number} rad angle (in radians) to rotate
* @returns {quat} out
*/
quat.rotateZ = function (out, a, rad) {
rad *= 0.5;
var ax = a[0], ay = a[1], az = a[2], aw = a[3],
bz = Math.sin(rad), bw = Math.cos(rad);
out[0] = ax * bw + ay * bz;
out[1] = ay * bw - ax * bz;
out[2] = az * bw + aw * bz;
out[3] = aw * bw - az * bz;
return out;
};
/**
* Calculates the W component of a quat from the X, Y, and Z components.
* Assumes that quaternion is 1 unit in length.
* Any existing W component will be ignored.
*
* @param {quat} out the receiving quaternion
* @param {quat} a quat to calculate W component of
* @returns {quat} out
*/
quat.calculateW = function (out, a) {
var x = a[0], y = a[1], z = a[2];
out[0] = x;
out[1] = y;
out[2] = z;
out[3] = -Math.sqrt(Math.abs(1.0 - x * x - y * y - z * z));
return out;
};
/**
* Calculates the dot product of two quat's
*
* @param {quat} a the first operand
* @param {quat} b the second operand
* @returns {Number} dot product of a and b
* @function
*/
quat.dot = vec4.dot;
/**
* Performs a linear interpolation between two quat's
*
* @param {quat} out the receiving quaternion
* @param {quat} a the first operand
* @param {quat} b the second operand
* @param {Number} t interpolation amount between the two inputs
* @returns {quat} out
* @function
*/
quat.lerp = vec4.lerp;
/**
* Performs a spherical linear interpolation between two quat
*
* @param {quat} out the receiving quaternion
* @param {quat} a the first operand
* @param {quat} b the second operand
* @param {Number} t interpolation amount between the two inputs
* @returns {quat} out
*/
quat.slerp = function (out, a, b, t) {
// benchmarks:
// http://jsperf.com/quaternion-slerp-implementations
var ax = a[0], ay = a[1], az = a[2], aw = a[3],
bx = b[0], by = b[1], bz = b[2], bw = b[3];
var omega, cosom, sinom, scale0, scale1;
// calc cosine
cosom = ax * bx + ay * by + az * bz + aw * bw;
// adjust signs (if necessary)
if ( cosom < 0.0 ) {
cosom = -cosom;
bx = - bx;
by = - by;
bz = - bz;
bw = - bw;
}
// calculate coefficients
if ( (1.0 - cosom) > 0.000001 ) {
// standard case (slerp)
omega = Math.acos(cosom);
sinom = Math.sin(omega);
scale0 = Math.sin((1.0 - t) * omega) / sinom;
scale1 = Math.sin(t * omega) / sinom;
} else {
// "from" and "to" quaternions are very close
// ... so we can do a linear interpolation
scale0 = 1.0 - t;
scale1 = t;
}
// calculate final values
out[0] = scale0 * ax + scale1 * bx;
out[1] = scale0 * ay + scale1 * by;
out[2] = scale0 * az + scale1 * bz;
out[3] = scale0 * aw + scale1 * bw;
return out;
};
/**
* Calculates the inverse of a quat
*
* @param {quat} out the receiving quaternion
* @param {quat} a quat to calculate inverse of
* @returns {quat} out
*/
quat.invert = function(out, a) {
var a0 = a[0], a1 = a[1], a2 = a[2], a3 = a[3],
dot = a0*a0 + a1*a1 + a2*a2 + a3*a3,
invDot = dot ? 1.0/dot : 0;
// TODO: Would be faster to return [0,0,0,0] immediately if dot == 0
out[0] = -a0*invDot;
out[1] = -a1*invDot;
out[2] = -a2*invDot;
out[3] = a3*invDot;
return out;
};
/**
* Calculates the conjugate of a quat
* If the quaternion is normalized, this function is faster than quat.inverse and produces the same result.
*
* @param {quat} out the receiving quaternion
* @param {quat} a quat to calculate conjugate of
* @returns {quat} out
*/
quat.conjugate = function (out, a) {
out[0] = -a[0];
out[1] = -a[1];
out[2] = -a[2];
out[3] = a[3];
return out;
};
/**
* Calculates the length of a quat
*
* @param {quat} a vector to calculate length of
* @returns {Number} length of a
* @function
*/
quat.length = vec4.length;
/**
* Alias for {@link quat.length}
* @function
*/
quat.len = quat.length;
/**
* Calculates the squared length of a quat
*
* @param {quat} a vector to calculate squared length of
* @returns {Number} squared length of a
* @function
*/
quat.squaredLength = vec4.squaredLength;
/**
* Alias for {@link quat.squaredLength}
* @function
*/
quat.sqrLen = quat.squaredLength;
/**
* Normalize a quat
*
* @param {quat} out the receiving quaternion
* @param {quat} a quaternion to normalize
* @returns {quat} out
* @function
*/
quat.normalize = vec4.normalize;
/**
* Creates a quaternion from the given 3x3 rotation matrix.
*
* NOTE: The resultant quaternion is not normalized, so you should be sure
* to renormalize the quaternion yourself where necessary.
*
* @param {quat} out the receiving quaternion
* @param {mat3} m rotation matrix
* @returns {quat} out
* @function
*/
quat.fromMat3 = function(out, m) {
// Algorithm in Ken Shoemake's article in 1987 SIGGRAPH course notes
// article "Quaternion Calculus and Fast Animation".
var fTrace = m[0] + m[4] + m[8];
var fRoot;
if ( fTrace > 0.0 ) {
// |w| > 1/2, may as well choose w > 1/2
fRoot = Math.sqrt(fTrace + 1.0); // 2w
out[3] = 0.5 * fRoot;
fRoot = 0.5/fRoot; // 1/(4w)
out[0] = (m[7]-m[5])*fRoot;
out[1] = (m[2]-m[6])*fRoot;
out[2] = (m[3]-m[1])*fRoot;
} else {
// |w| <= 1/2
var i = 0;
if ( m[4] > m[0] )
i = 1;
if ( m[8] > m[i*3+i] )
i = 2;
var j = (i+1)%3;
var k = (i+2)%3;
fRoot = Math.sqrt(m[i*3+i]-m[j*3+j]-m[k*3+k] + 1.0);
out[i] = 0.5 * fRoot;
fRoot = 0.5 / fRoot;
out[3] = (m[k*3+j] - m[j*3+k]) * fRoot;
out[j] = (m[j*3+i] + m[i*3+j]) * fRoot;
out[k] = (m[k*3+i] + m[i*3+k]) * fRoot;
}
return out;
};
/**
* Returns a string representation of a quatenion
*
* @param {quat} vec vector to represent as a string
* @returns {String} string representation of the vector
*/
quat.str = function (a) {
return 'quat(' + a[0] + ', ' + a[1] + ', ' + a[2] + ', ' + a[3] + ')';
};
export default quat;

View File

@@ -0,0 +1,538 @@
import {GLMAT_ARRAY_TYPE} from "./common";
import {GLMAT_RANDOM} from "./common";
/* Copyright (c) 2013, Brandon Jones, Colin MacKenzie IV. All rights reserved.
Redistribution and use in source and binary forms, with or without modification,
are permitted provided that the following conditions are met:
* Redistributions of source code must retain the above copyright notice, this
list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */
/**
* @class 2 Dimensional Vector
* @name vec2
*/
var vec2 = {};
/**
* Creates a new, empty vec2
*
* @returns {vec2} a new 2D vector
*/
vec2.create = function() {
var out = new GLMAT_ARRAY_TYPE(2);
out[0] = 0;
out[1] = 0;
return out;
};
/**
* Creates a new vec2 initialized with values from an existing vector
*
* @param {vec2} a vector to clone
* @returns {vec2} a new 2D vector
*/
vec2.clone = function(a) {
var out = new GLMAT_ARRAY_TYPE(2);
out[0] = a[0];
out[1] = a[1];
return out;
};
/**
* Creates a new vec2 initialized with the given values
*
* @param {Number} x X component
* @param {Number} y Y component
* @returns {vec2} a new 2D vector
*/
vec2.fromValues = function(x, y) {
var out = new GLMAT_ARRAY_TYPE(2);
out[0] = x;
out[1] = y;
return out;
};
/**
* Copy the values from one vec2 to another
*
* @param {vec2} out the receiving vector
* @param {vec2} a the source vector
* @returns {vec2} out
*/
vec2.copy = function(out, a) {
out[0] = a[0];
out[1] = a[1];
return out;
};
/**
* Set the components of a vec2 to the given values
*
* @param {vec2} out the receiving vector
* @param {Number} x X component
* @param {Number} y Y component
* @returns {vec2} out
*/
vec2.set = function(out, x, y) {
out[0] = x;
out[1] = y;
return out;
};
/**
* Adds two vec2's
*
* @param {vec2} out the receiving vector
* @param {vec2} a the first operand
* @param {vec2} b the second operand
* @returns {vec2} out
*/
vec2.add = function(out, a, b) {
out[0] = a[0] + b[0];
out[1] = a[1] + b[1];
return out;
};
/**
* Subtracts vector b from vector a
*
* @param {vec2} out the receiving vector
* @param {vec2} a the first operand
* @param {vec2} b the second operand
* @returns {vec2} out
*/
vec2.subtract = function(out, a, b) {
out[0] = a[0] - b[0];
out[1] = a[1] - b[1];
return out;
};
/**
* Alias for {@link vec2.subtract}
* @function
*/
vec2.sub = vec2.subtract;
/**
* Multiplies two vec2's
*
* @param {vec2} out the receiving vector
* @param {vec2} a the first operand
* @param {vec2} b the second operand
* @returns {vec2} out
*/
vec2.multiply = function(out, a, b) {
out[0] = a[0] * b[0];
out[1] = a[1] * b[1];
return out;
};
/**
* Alias for {@link vec2.multiply}
* @function
*/
vec2.mul = vec2.multiply;
/**
* Divides two vec2's
*
* @param {vec2} out the receiving vector
* @param {vec2} a the first operand
* @param {vec2} b the second operand
* @returns {vec2} out
*/
vec2.divide = function(out, a, b) {
out[0] = a[0] / b[0];
out[1] = a[1] / b[1];
return out;
};
/**
* Alias for {@link vec2.divide}
* @function
*/
vec2.div = vec2.divide;
/**
* Returns the minimum of two vec2's
*
* @param {vec2} out the receiving vector
* @param {vec2} a the first operand
* @param {vec2} b the second operand
* @returns {vec2} out
*/
vec2.min = function(out, a, b) {
out[0] = Math.min(a[0], b[0]);
out[1] = Math.min(a[1], b[1]);
return out;
};
/**
* Returns the maximum of two vec2's
*
* @param {vec2} out the receiving vector
* @param {vec2} a the first operand
* @param {vec2} b the second operand
* @returns {vec2} out
*/
vec2.max = function(out, a, b) {
out[0] = Math.max(a[0], b[0]);
out[1] = Math.max(a[1], b[1]);
return out;
};
/**
* Scales a vec2 by a scalar number
*
* @param {vec2} out the receiving vector
* @param {vec2} a the vector to scale
* @param {Number} b amount to scale the vector by
* @returns {vec2} out
*/
vec2.scale = function(out, a, b) {
out[0] = a[0] * b;
out[1] = a[1] * b;
return out;
};
/**
* Adds two vec2's after scaling the second operand by a scalar value
*
* @param {vec2} out the receiving vector
* @param {vec2} a the first operand
* @param {vec2} b the second operand
* @param {Number} scale the amount to scale b by before adding
* @returns {vec2} out
*/
vec2.scaleAndAdd = function(out, a, b, scale) {
out[0] = a[0] + (b[0] * scale);
out[1] = a[1] + (b[1] * scale);
return out;
};
/**
* Calculates the euclidian distance between two vec2's
*
* @param {vec2} a the first operand
* @param {vec2} b the second operand
* @returns {Number} distance between a and b
*/
vec2.distance = function(a, b) {
var x = b[0] - a[0],
y = b[1] - a[1];
return Math.sqrt(x*x + y*y);
};
/**
* Alias for {@link vec2.distance}
* @function
*/
vec2.dist = vec2.distance;
/**
* Calculates the squared euclidian distance between two vec2's
*
* @param {vec2} a the first operand
* @param {vec2} b the second operand
* @returns {Number} squared distance between a and b
*/
vec2.squaredDistance = function(a, b) {
var x = b[0] - a[0],
y = b[1] - a[1];
return x*x + y*y;
};
/**
* Alias for {@link vec2.squaredDistance}
* @function
*/
vec2.sqrDist = vec2.squaredDistance;
/**
* Calculates the length of a vec2
*
* @param {vec2} a vector to calculate length of
* @returns {Number} length of a
*/
vec2.length = function (a) {
var x = a[0],
y = a[1];
return Math.sqrt(x*x + y*y);
};
/**
* Alias for {@link vec2.length}
* @function
*/
vec2.len = vec2.length;
/**
* Calculates the squared length of a vec2
*
* @param {vec2} a vector to calculate squared length of
* @returns {Number} squared length of a
*/
vec2.squaredLength = function (a) {
var x = a[0],
y = a[1];
return x*x + y*y;
};
/**
* Alias for {@link vec2.squaredLength}
* @function
*/
vec2.sqrLen = vec2.squaredLength;
/**
* Negates the components of a vec2
*
* @param {vec2} out the receiving vector
* @param {vec2} a vector to negate
* @returns {vec2} out
*/
vec2.negate = function(out, a) {
out[0] = -a[0];
out[1] = -a[1];
return out;
};
/**
* Normalize a vec2
*
* @param {vec2} out the receiving vector
* @param {vec2} a vector to normalize
* @returns {vec2} out
*/
vec2.normalize = function(out, a) {
var x = a[0],
y = a[1];
var len = x*x + y*y;
if (len > 0) {
//TODO: evaluate use of glm_invsqrt here?
len = 1 / Math.sqrt(len);
out[0] = a[0] * len;
out[1] = a[1] * len;
}
return out;
};
/**
* Calculates the dot product of two vec2's
*
* @param {vec2} a the first operand
* @param {vec2} b the second operand
* @returns {Number} dot product of a and b
*/
vec2.dot = function (a, b) {
return a[0] * b[0] + a[1] * b[1];
};
/**
* Computes the cross product of two vec2's
* Note that the cross product must by definition produce a 3D vector
*
* @param {vec3} out the receiving vector
* @param {vec2} a the first operand
* @param {vec2} b the second operand
* @returns {vec3} out
*/
vec2.cross = function(out, a, b) {
var z = a[0] * b[1] - a[1] * b[0];
out[0] = out[1] = 0;
out[2] = z;
return out;
};
/**
* Performs a linear interpolation between two vec2's
*
* @param {vec2} out the receiving vector
* @param {vec2} a the first operand
* @param {vec2} b the second operand
* @param {Number} t interpolation amount between the two inputs
* @returns {vec2} out
*/
vec2.lerp = function (out, a, b, t) {
var ax = a[0],
ay = a[1];
out[0] = ax + t * (b[0] - ax);
out[1] = ay + t * (b[1] - ay);
return out;
};
/**
* Generates a random vector with the given scale
*
* @param {vec2} out the receiving vector
* @param {Number} [scale] Length of the resulting vector. If ommitted, a unit vector will be returned
* @returns {vec2} out
*/
vec2.random = function (out, scale) {
scale = scale || 1.0;
var r = GLMAT_RANDOM() * 2.0 * Math.PI;
out[0] = Math.cos(r) * scale;
out[1] = Math.sin(r) * scale;
return out;
};
/**
* Transforms the vec2 with a mat2
*
* @param {vec2} out the receiving vector
* @param {vec2} a the vector to transform
* @param {mat2} m matrix to transform with
* @returns {vec2} out
*/
vec2.transformMat2 = function(out, a, m) {
var x = a[0],
y = a[1];
out[0] = m[0] * x + m[2] * y;
out[1] = m[1] * x + m[3] * y;
return out;
};
/**
* Transforms the vec2 with a mat2d
*
* @param {vec2} out the receiving vector
* @param {vec2} a the vector to transform
* @param {mat2d} m matrix to transform with
* @returns {vec2} out
*/
vec2.transformMat2d = function(out, a, m) {
var x = a[0],
y = a[1];
out[0] = m[0] * x + m[2] * y + m[4];
out[1] = m[1] * x + m[3] * y + m[5];
return out;
};
/**
* Transforms the vec2 with a mat3
* 3rd vector component is implicitly '1'
*
* @param {vec2} out the receiving vector
* @param {vec2} a the vector to transform
* @param {mat3} m matrix to transform with
* @returns {vec2} out
*/
vec2.transformMat3 = function(out, a, m) {
var x = a[0],
y = a[1];
out[0] = m[0] * x + m[3] * y + m[6];
out[1] = m[1] * x + m[4] * y + m[7];
return out;
};
/**
* Transforms the vec2 with a mat4
* 3rd vector component is implicitly '0'
* 4th vector component is implicitly '1'
*
* @param {vec2} out the receiving vector
* @param {vec2} a the vector to transform
* @param {mat4} m matrix to transform with
* @returns {vec2} out
*/
vec2.transformMat4 = function(out, a, m) {
var x = a[0],
y = a[1];
out[0] = m[0] * x + m[4] * y + m[12];
out[1] = m[1] * x + m[5] * y + m[13];
return out;
};
/**
* Perform some operation over an array of vec2s.
*
* @param {Array} a the array of vectors to iterate over
* @param {Number} stride Number of elements between the start of each vec2. If 0 assumes tightly packed
* @param {Number} offset Number of elements to skip at the beginning of the array
* @param {Number} count Number of vec2s to iterate over. If 0 iterates over entire array
* @param {Function} fn Function to call for each vector in the array
* @param {Object} [arg] additional argument to pass to fn
* @returns {Array} a
* @function
*/
vec2.forEach = (function() {
var vec = vec2.create();
return function(a, stride, offset, count, fn, arg) {
var i, l;
if(!stride) {
stride = 2;
}
if(!offset) {
offset = 0;
}
if(count) {
l = Math.min((count * stride) + offset, a.length);
} else {
l = a.length;
}
for(i = offset; i < l; i += stride) {
vec[0] = a[i]; vec[1] = a[i+1];
fn(vec, vec, arg);
a[i] = vec[0]; a[i+1] = vec[1];
}
return a;
};
})();
/**
* Returns a string representation of a vector
*
* @param {vec2} vec vector to represent as a string
* @returns {String} string representation of the vector
*/
vec2.str = function (a) {
return 'vec2(' + a[0] + ', ' + a[1] + ')';
};
vec2.multiplyScalar = function(out, a, b) {
out[0] = a[0] * b;
out[1] = a[1] * b;
return out;
};
vec2.clear = function(out) {
out[0] = 0;
out[1] = 0;
return out;
};
vec2.addXY = function(out, a, x, y) {
out[0] = a[0] + x;
out[1] = a[1] + y;
return out;
};
export default vec2;

View File

@@ -0,0 +1,562 @@
import {GLMAT_ARRAY_TYPE} from "./common";
import {GLMAT_RANDOM} from "./common";
/* Copyright (c) 2013, Brandon Jones, Colin MacKenzie IV. All rights reserved.
Redistribution and use in source and binary forms, with or without modification,
are permitted provided that the following conditions are met:
* Redistributions of source code must retain the above copyright notice, this
list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */
/**
* @class 3 Dimensional Vector
* @name vec3
*/
var vec3 = {};
/**
* Creates a new, empty vec3
*
* @returns {vec3} a new 3D vector
*/
vec3.create = function() {
var out = new GLMAT_ARRAY_TYPE(3);
out[0] = 0;
out[1] = 0;
out[2] = 0;
return out;
};
/**
* Creates a new vec3 initialized with values from an existing vector
*
* @param {vec3} a vector to clone
* @returns {vec3} a new 3D vector
*/
vec3.clone = function(a) {
var out = new GLMAT_ARRAY_TYPE(3);
out[0] = a[0];
out[1] = a[1];
out[2] = a[2];
return out;
};
/**
* Creates a new vec3 initialized with the given values
*
* @param {Number} x X component
* @param {Number} y Y component
* @param {Number} z Z component
* @returns {vec3} a new 3D vector
*/
vec3.fromValues = function(x, y, z) {
var out = new GLMAT_ARRAY_TYPE(3);
out[0] = x;
out[1] = y;
out[2] = z;
return out;
};
/**
* Copy the values from one vec3 to another
*
* @param {vec3} out the receiving vector
* @param {vec3} a the source vector
* @returns {vec3} out
*/
vec3.copy = function(out, a) {
out[0] = a[0];
out[1] = a[1];
out[2] = a[2];
return out;
};
/**
* Set the components of a vec3 to the given values
*
* @param {vec3} out the receiving vector
* @param {Number} x X component
* @param {Number} y Y component
* @param {Number} z Z component
* @returns {vec3} out
*/
vec3.set = function(out, x, y, z) {
out[0] = x;
out[1] = y;
out[2] = z;
return out;
};
/**
* Adds two vec3's
*
* @param {vec3} out the receiving vector
* @param {vec3} a the first operand
* @param {vec3} b the second operand
* @returns {vec3} out
*/
vec3.add = function(out, a, b) {
out[0] = a[0] + b[0];
out[1] = a[1] + b[1];
out[2] = a[2] + b[2];
return out;
};
/**
* Subtracts vector b from vector a
*
* @param {vec3} out the receiving vector
* @param {vec3} a the first operand
* @param {vec3} b the second operand
* @returns {vec3} out
*/
vec3.subtract = function(out, a, b) {
out[0] = a[0] - b[0];
out[1] = a[1] - b[1];
out[2] = a[2] - b[2];
return out;
};
/**
* Alias for {@link vec3.subtract}
* @function
*/
vec3.sub = vec3.subtract;
/**
* Multiplies two vec3's
*
* @param {vec3} out the receiving vector
* @param {vec3} a the first operand
* @param {vec3} b the second operand
* @returns {vec3} out
*/
vec3.multiply = function(out, a, b) {
out[0] = a[0] * b[0];
out[1] = a[1] * b[1];
out[2] = a[2] * b[2];
return out;
};
/**
* Alias for {@link vec3.multiply}
* @function
*/
vec3.mul = vec3.multiply;
/**
* Divides two vec3's
*
* @param {vec3} out the receiving vector
* @param {vec3} a the first operand
* @param {vec3} b the second operand
* @returns {vec3} out
*/
vec3.divide = function(out, a, b) {
out[0] = a[0] / b[0];
out[1] = a[1] / b[1];
out[2] = a[2] / b[2];
return out;
};
/**
* Alias for {@link vec3.divide}
* @function
*/
vec3.div = vec3.divide;
/**
* Returns the minimum of two vec3's
*
* @param {vec3} out the receiving vector
* @param {vec3} a the first operand
* @param {vec3} b the second operand
* @returns {vec3} out
*/
vec3.min = function(out, a, b) {
out[0] = Math.min(a[0], b[0]);
out[1] = Math.min(a[1], b[1]);
out[2] = Math.min(a[2], b[2]);
return out;
};
/**
* Returns the maximum of two vec3's
*
* @param {vec3} out the receiving vector
* @param {vec3} a the first operand
* @param {vec3} b the second operand
* @returns {vec3} out
*/
vec3.max = function(out, a, b) {
out[0] = Math.max(a[0], b[0]);
out[1] = Math.max(a[1], b[1]);
out[2] = Math.max(a[2], b[2]);
return out;
};
/**
* Scales a vec3 by a scalar number
*
* @param {vec3} out the receiving vector
* @param {vec3} a the vector to scale
* @param {Number} b amount to scale the vector by
* @returns {vec3} out
*/
vec3.scale = function(out, a, b) {
out[0] = a[0] * b;
out[1] = a[1] * b;
out[2] = a[2] * b;
return out;
};
/**
* Adds two vec3's after scaling the second operand by a scalar value
*
* @param {vec3} out the receiving vector
* @param {vec3} a the first operand
* @param {vec3} b the second operand
* @param {Number} scale the amount to scale b by before adding
* @returns {vec3} out
*/
vec3.scaleAndAdd = function(out, a, b, scale) {
out[0] = a[0] + (b[0] * scale);
out[1] = a[1] + (b[1] * scale);
out[2] = a[2] + (b[2] * scale);
return out;
};
/**
* Calculates the euclidian distance between two vec3's
*
* @param {vec3} a the first operand
* @param {vec3} b the second operand
* @returns {Number} distance between a and b
*/
vec3.distance = function(a, b) {
var x = b[0] - a[0],
y = b[1] - a[1],
z = b[2] - a[2];
return Math.sqrt(x*x + y*y + z*z);
};
/**
* Alias for {@link vec3.distance}
* @function
*/
vec3.dist = vec3.distance;
/**
* Calculates the squared euclidian distance between two vec3's
*
* @param {vec3} a the first operand
* @param {vec3} b the second operand
* @returns {Number} squared distance between a and b
*/
vec3.squaredDistance = function(a, b) {
var x = b[0] - a[0],
y = b[1] - a[1],
z = b[2] - a[2];
return x*x + y*y + z*z;
};
/**
* Alias for {@link vec3.squaredDistance}
* @function
*/
vec3.sqrDist = vec3.squaredDistance;
/**
* Calculates the length of a vec3
*
* @param {vec3} a vector to calculate length of
* @returns {Number} length of a
*/
vec3.length = function (a) {
var x = a[0],
y = a[1],
z = a[2];
return Math.sqrt(x*x + y*y + z*z);
};
/**
* Alias for {@link vec3.length}
* @function
*/
vec3.len = vec3.length;
/**
* Calculates the squared length of a vec3
*
* @param {vec3} a vector to calculate squared length of
* @returns {Number} squared length of a
*/
vec3.squaredLength = function (a) {
var x = a[0],
y = a[1],
z = a[2];
return x*x + y*y + z*z;
};
/**
* Alias for {@link vec3.squaredLength}
* @function
*/
vec3.sqrLen = vec3.squaredLength;
/**
* Negates the components of a vec3
*
* @param {vec3} out the receiving vector
* @param {vec3} a vector to negate
* @returns {vec3} out
*/
vec3.negate = function(out, a) {
out[0] = -a[0];
out[1] = -a[1];
out[2] = -a[2];
return out;
};
/**
* Normalize a vec3
*
* @param {vec3} out the receiving vector
* @param {vec3} a vector to normalize
* @returns {vec3} out
*/
vec3.normalize = function(out, a) {
var x = a[0],
y = a[1],
z = a[2];
var len = x*x + y*y + z*z;
if (len > 0) {
//TODO: evaluate use of glm_invsqrt here?
len = 1 / Math.sqrt(len);
out[0] = a[0] * len;
out[1] = a[1] * len;
out[2] = a[2] * len;
}
return out;
};
/**
* Calculates the dot product of two vec3's
*
* @param {vec3} a the first operand
* @param {vec3} b the second operand
* @returns {Number} dot product of a and b
*/
vec3.dot = function (a, b) {
return a[0] * b[0] + a[1] * b[1] + a[2] * b[2];
};
/**
* Computes the cross product of two vec3's
*
* @param {vec3} out the receiving vector
* @param {vec3} a the first operand
* @param {vec3} b the second operand
* @returns {vec3} out
*/
vec3.cross = function(out, a, b) {
var ax = a[0], ay = a[1], az = a[2],
bx = b[0], by = b[1], bz = b[2];
out[0] = ay * bz - az * by;
out[1] = az * bx - ax * bz;
out[2] = ax * by - ay * bx;
return out;
};
/**
* Performs a linear interpolation between two vec3's
*
* @param {vec3} out the receiving vector
* @param {vec3} a the first operand
* @param {vec3} b the second operand
* @param {Number} t interpolation amount between the two inputs
* @returns {vec3} out
*/
vec3.lerp = function (out, a, b, t) {
var ax = a[0],
ay = a[1],
az = a[2];
out[0] = ax + t * (b[0] - ax);
out[1] = ay + t * (b[1] - ay);
out[2] = az + t * (b[2] - az);
return out;
};
/**
* Generates a random vector with the given scale
*
* @param {vec3} out the receiving vector
* @param {Number} [scale] Length of the resulting vector. If ommitted, a unit vector will be returned
* @returns {vec3} out
*/
vec3.random = function (out, scale) {
scale = scale || 1.0;
var r = GLMAT_RANDOM() * 2.0 * Math.PI;
var z = (GLMAT_RANDOM() * 2.0) - 1.0;
var zScale = Math.sqrt(1.0-z*z) * scale;
out[0] = Math.cos(r) * zScale;
out[1] = Math.sin(r) * zScale;
out[2] = z * scale;
return out;
};
/**
* Transforms the vec3 with a mat4.
* 4th vector component is implicitly '1'
*
* @param {vec3} out the receiving vector
* @param {vec3} a the vector to transform
* @param {mat4} m matrix to transform with
* @returns {vec3} out
*/
vec3.transformMat4 = function(out, a, m) {
var x = a[0], y = a[1], z = a[2];
out[0] = m[0] * x + m[4] * y + m[8] * z + m[12];
out[1] = m[1] * x + m[5] * y + m[9] * z + m[13];
out[2] = m[2] * x + m[6] * y + m[10] * z + m[14];
return out;
};
/**
* Transforms the vec3 with a mat3.
*
* @param {vec3} out the receiving vector
* @param {vec3} a the vector to transform
* @param {mat4} m the 3x3 matrix to transform with
* @returns {vec3} out
*/
vec3.transformMat3 = function(out, a, m) {
var x = a[0], y = a[1], z = a[2];
out[0] = x * m[0] + y * m[3] + z * m[6];
out[1] = x * m[1] + y * m[4] + z * m[7];
out[2] = x * m[2] + y * m[5] + z * m[8];
return out;
};
/**
* Transforms the vec3 with a quat
*
* @param {vec3} out the receiving vector
* @param {vec3} a the vector to transform
* @param {quat} q quaternion to transform with
* @returns {vec3} out
*/
vec3.transformQuat = function(out, a, q) {
// benchmarks: http://jsperf.com/quaternion-transform-vec3-implementations
var x = a[0], y = a[1], z = a[2],
qx = q[0], qy = q[1], qz = q[2], qw = q[3],
// calculate quat * vec
ix = qw * x + qy * z - qz * y,
iy = qw * y + qz * x - qx * z,
iz = qw * z + qx * y - qy * x,
iw = -qx * x - qy * y - qz * z;
// calculate result * inverse quat
out[0] = ix * qw + iw * -qx + iy * -qz - iz * -qy;
out[1] = iy * qw + iw * -qy + iz * -qx - ix * -qz;
out[2] = iz * qw + iw * -qz + ix * -qy - iy * -qx;
return out;
};
/**
* Perform some operation over an array of vec3s.
*
* @param {Array} a the array of vectors to iterate over
* @param {Number} stride Number of elements between the start of each vec3. If 0 assumes tightly packed
* @param {Number} offset Number of elements to skip at the beginning of the array
* @param {Number} count Number of vec3s to iterate over. If 0 iterates over entire array
* @param {Function} fn Function to call for each vector in the array
* @param {Object} [arg] additional argument to pass to fn
* @returns {Array} a
* @function
*/
vec3.forEach = (function() {
var vec = vec3.create();
return function(a, stride, offset, count, fn, arg) {
var i, l;
if(!stride) {
stride = 3;
}
if(!offset) {
offset = 0;
}
if(count) {
l = Math.min((count * stride) + offset, a.length);
} else {
l = a.length;
}
for(i = offset; i < l; i += stride) {
vec[0] = a[i]; vec[1] = a[i+1]; vec[2] = a[i+2];
fn(vec, vec, arg);
a[i] = vec[0]; a[i+1] = vec[1]; a[i+2] = vec[2];
}
return a;
};
})();
/**
* Returns a string representation of a vector
*
* @param {vec3} vec vector to represent as a string
* @returns {String} string representation of the vector
*/
vec3.str = function (a) {
return 'vec3(' + a[0] + ', ' + a[1] + ', ' + a[2] + ')';
};
vec3.multiplyScalar = function(out, a, b) {
out[0] = a[0] * b;
out[1] = a[1] * b;
out[2] = a[2] * b;
return out;
};
vec3.clear = function(out) {
out[0] = 0;
out[1] = 0;
out[2] = 0;
return out;
};
vec3.addXYZ = function(out, a, x, y, z) {
out[0] = a[0] + x;
out[1] = a[1] + y;
out[2] = a[2] + z;
return out;
};
export default vec3;

View File

@@ -0,0 +1,526 @@
import {GLMAT_ARRAY_TYPE} from "./common";
import {GLMAT_RANDOM} from "./common";
/* Copyright (c) 2013, Brandon Jones, Colin MacKenzie IV. All rights reserved.
Redistribution and use in source and binary forms, with or without modification,
are permitted provided that the following conditions are met:
* Redistributions of source code must retain the above copyright notice, this
list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */
/**
* @class 4 Dimensional Vector
* @name vec4
*/
var vec4 = {};
/**
* Creates a new, empty vec4
*
* @returns {vec4} a new 4D vector
*/
vec4.create = function() {
var out = new GLMAT_ARRAY_TYPE(4);
out[0] = 0;
out[1] = 0;
out[2] = 0;
out[3] = 0;
return out;
};
/**
* Creates a new vec4 initialized with values from an existing vector
*
* @param {vec4} a vector to clone
* @returns {vec4} a new 4D vector
*/
vec4.clone = function(a) {
var out = new GLMAT_ARRAY_TYPE(4);
out[0] = a[0];
out[1] = a[1];
out[2] = a[2];
out[3] = a[3];
return out;
};
/**
* Creates a new vec4 initialized with the given values
*
* @param {Number} x X component
* @param {Number} y Y component
* @param {Number} z Z component
* @param {Number} w W component
* @returns {vec4} a new 4D vector
*/
vec4.fromValues = function(x, y, z, w) {
var out = new GLMAT_ARRAY_TYPE(4);
out[0] = x;
out[1] = y;
out[2] = z;
out[3] = w;
return out;
};
/**
* Copy the values from one vec4 to another
*
* @param {vec4} out the receiving vector
* @param {vec4} a the source vector
* @returns {vec4} out
*/
vec4.copy = function(out, a) {
out[0] = a[0];
out[1] = a[1];
out[2] = a[2];
out[3] = a[3];
return out;
};
/**
* Set the components of a vec4 to the given values
*
* @param {vec4} out the receiving vector
* @param {Number} x X component
* @param {Number} y Y component
* @param {Number} z Z component
* @param {Number} w W component
* @returns {vec4} out
*/
vec4.set = function(out, x, y, z, w) {
out[0] = x;
out[1] = y;
out[2] = z;
out[3] = w;
return out;
};
/**
* Adds two vec4's
*
* @param {vec4} out the receiving vector
* @param {vec4} a the first operand
* @param {vec4} b the second operand
* @returns {vec4} out
*/
vec4.add = function(out, a, b) {
out[0] = a[0] + b[0];
out[1] = a[1] + b[1];
out[2] = a[2] + b[2];
out[3] = a[3] + b[3];
return out;
};
/**
* Subtracts vector b from vector a
*
* @param {vec4} out the receiving vector
* @param {vec4} a the first operand
* @param {vec4} b the second operand
* @returns {vec4} out
*/
vec4.subtract = function(out, a, b) {
out[0] = a[0] - b[0];
out[1] = a[1] - b[1];
out[2] = a[2] - b[2];
out[3] = a[3] - b[3];
return out;
};
/**
* Alias for {@link vec4.subtract}
* @function
*/
vec4.sub = vec4.subtract;
/**
* Multiplies two vec4's
*
* @param {vec4} out the receiving vector
* @param {vec4} a the first operand
* @param {vec4} b the second operand
* @returns {vec4} out
*/
vec4.multiply = function(out, a, b) {
out[0] = a[0] * b[0];
out[1] = a[1] * b[1];
out[2] = a[2] * b[2];
out[3] = a[3] * b[3];
return out;
};
/**
* Alias for {@link vec4.multiply}
* @function
*/
vec4.mul = vec4.multiply;
/**
* Divides two vec4's
*
* @param {vec4} out the receiving vector
* @param {vec4} a the first operand
* @param {vec4} b the second operand
* @returns {vec4} out
*/
vec4.divide = function(out, a, b) {
out[0] = a[0] / b[0];
out[1] = a[1] / b[1];
out[2] = a[2] / b[2];
out[3] = a[3] / b[3];
return out;
};
/**
* Alias for {@link vec4.divide}
* @function
*/
vec4.div = vec4.divide;
/**
* Returns the minimum of two vec4's
*
* @param {vec4} out the receiving vector
* @param {vec4} a the first operand
* @param {vec4} b the second operand
* @returns {vec4} out
*/
vec4.min = function(out, a, b) {
out[0] = Math.min(a[0], b[0]);
out[1] = Math.min(a[1], b[1]);
out[2] = Math.min(a[2], b[2]);
out[3] = Math.min(a[3], b[3]);
return out;
};
/**
* Returns the maximum of two vec4's
*
* @param {vec4} out the receiving vector
* @param {vec4} a the first operand
* @param {vec4} b the second operand
* @returns {vec4} out
*/
vec4.max = function(out, a, b) {
out[0] = Math.max(a[0], b[0]);
out[1] = Math.max(a[1], b[1]);
out[2] = Math.max(a[2], b[2]);
out[3] = Math.max(a[3], b[3]);
return out;
};
/**
* Scales a vec4 by a scalar number
*
* @param {vec4} out the receiving vector
* @param {vec4} a the vector to scale
* @param {Number} b amount to scale the vector by
* @returns {vec4} out
*/
vec4.scale = function(out, a, b) {
out[0] = a[0] * b;
out[1] = a[1] * b;
out[2] = a[2] * b;
out[3] = a[3] * b;
return out;
};
/**
* Adds two vec4's after scaling the second operand by a scalar value
*
* @param {vec4} out the receiving vector
* @param {vec4} a the first operand
* @param {vec4} b the second operand
* @param {Number} scale the amount to scale b by before adding
* @returns {vec4} out
*/
vec4.scaleAndAdd = function(out, a, b, scale) {
out[0] = a[0] + (b[0] * scale);
out[1] = a[1] + (b[1] * scale);
out[2] = a[2] + (b[2] * scale);
out[3] = a[3] + (b[3] * scale);
return out;
};
/**
* Calculates the euclidian distance between two vec4's
*
* @param {vec4} a the first operand
* @param {vec4} b the second operand
* @returns {Number} distance between a and b
*/
vec4.distance = function(a, b) {
var x = b[0] - a[0],
y = b[1] - a[1],
z = b[2] - a[2],
w = b[3] - a[3];
return Math.sqrt(x*x + y*y + z*z + w*w);
};
/**
* Alias for {@link vec4.distance}
* @function
*/
vec4.dist = vec4.distance;
/**
* Calculates the squared euclidian distance between two vec4's
*
* @param {vec4} a the first operand
* @param {vec4} b the second operand
* @returns {Number} squared distance between a and b
*/
vec4.squaredDistance = function(a, b) {
var x = b[0] - a[0],
y = b[1] - a[1],
z = b[2] - a[2],
w = b[3] - a[3];
return x*x + y*y + z*z + w*w;
};
/**
* Alias for {@link vec4.squaredDistance}
* @function
*/
vec4.sqrDist = vec4.squaredDistance;
/**
* Calculates the length of a vec4
*
* @param {vec4} a vector to calculate length of
* @returns {Number} length of a
*/
vec4.length = function (a) {
var x = a[0],
y = a[1],
z = a[2],
w = a[3];
return Math.sqrt(x*x + y*y + z*z + w*w);
};
/**
* Alias for {@link vec4.length}
* @function
*/
vec4.len = vec4.length;
/**
* Calculates the squared length of a vec4
*
* @param {vec4} a vector to calculate squared length of
* @returns {Number} squared length of a
*/
vec4.squaredLength = function (a) {
var x = a[0],
y = a[1],
z = a[2],
w = a[3];
return x*x + y*y + z*z + w*w;
};
/**
* Alias for {@link vec4.squaredLength}
* @function
*/
vec4.sqrLen = vec4.squaredLength;
/**
* Negates the components of a vec4
*
* @param {vec4} out the receiving vector
* @param {vec4} a vector to negate
* @returns {vec4} out
*/
vec4.negate = function(out, a) {
out[0] = -a[0];
out[1] = -a[1];
out[2] = -a[2];
out[3] = -a[3];
return out;
};
/**
* Normalize a vec4
*
* @param {vec4} out the receiving vector
* @param {vec4} a vector to normalize
* @returns {vec4} out
*/
vec4.normalize = function(out, a) {
var x = a[0],
y = a[1],
z = a[2],
w = a[3];
var len = x*x + y*y + z*z + w*w;
if (len > 0) {
len = 1 / Math.sqrt(len);
out[0] = a[0] * len;
out[1] = a[1] * len;
out[2] = a[2] * len;
out[3] = a[3] * len;
}
return out;
};
/**
* Calculates the dot product of two vec4's
*
* @param {vec4} a the first operand
* @param {vec4} b the second operand
* @returns {Number} dot product of a and b
*/
vec4.dot = function (a, b) {
return a[0] * b[0] + a[1] * b[1] + a[2] * b[2] + a[3] * b[3];
};
/**
* Performs a linear interpolation between two vec4's
*
* @param {vec4} out the receiving vector
* @param {vec4} a the first operand
* @param {vec4} b the second operand
* @param {Number} t interpolation amount between the two inputs
* @returns {vec4} out
*/
vec4.lerp = function (out, a, b, t) {
var ax = a[0],
ay = a[1],
az = a[2],
aw = a[3];
out[0] = ax + t * (b[0] - ax);
out[1] = ay + t * (b[1] - ay);
out[2] = az + t * (b[2] - az);
out[3] = aw + t * (b[3] - aw);
return out;
};
/**
* Generates a random vector with the given scale
*
* @param {vec4} out the receiving vector
* @param {Number} [scale] Length of the resulting vector. If ommitted, a unit vector will be returned
* @returns {vec4} out
*/
vec4.random = function (out, scale) {
scale = scale || 1.0;
//TODO: This is a pretty awful way of doing this. Find something better.
out[0] = GLMAT_RANDOM();
out[1] = GLMAT_RANDOM();
out[2] = GLMAT_RANDOM();
out[3] = GLMAT_RANDOM();
vec4.normalize(out, out);
vec4.scale(out, out, scale);
return out;
};
/**
* Transforms the vec4 with a mat4.
*
* @param {vec4} out the receiving vector
* @param {vec4} a the vector to transform
* @param {mat4} m matrix to transform with
* @returns {vec4} out
*/
vec4.transformMat4 = function(out, a, m) {
var x = a[0], y = a[1], z = a[2], w = a[3];
out[0] = m[0] * x + m[4] * y + m[8] * z + m[12] * w;
out[1] = m[1] * x + m[5] * y + m[9] * z + m[13] * w;
out[2] = m[2] * x + m[6] * y + m[10] * z + m[14] * w;
out[3] = m[3] * x + m[7] * y + m[11] * z + m[15] * w;
return out;
};
/**
* Transforms the vec4 with a quat
*
* @param {vec4} out the receiving vector
* @param {vec4} a the vector to transform
* @param {quat} q quaternion to transform with
* @returns {vec4} out
*/
vec4.transformQuat = function(out, a, q) {
var x = a[0], y = a[1], z = a[2],
qx = q[0], qy = q[1], qz = q[2], qw = q[3],
// calculate quat * vec
ix = qw * x + qy * z - qz * y,
iy = qw * y + qz * x - qx * z,
iz = qw * z + qx * y - qy * x,
iw = -qx * x - qy * y - qz * z;
// calculate result * inverse quat
out[0] = ix * qw + iw * -qx + iy * -qz - iz * -qy;
out[1] = iy * qw + iw * -qy + iz * -qx - ix * -qz;
out[2] = iz * qw + iw * -qz + ix * -qy - iy * -qx;
return out;
};
/**
* Perform some operation over an array of vec4s.
*
* @param {Array} a the array of vectors to iterate over
* @param {Number} stride Number of elements between the start of each vec4. If 0 assumes tightly packed
* @param {Number} offset Number of elements to skip at the beginning of the array
* @param {Number} count Number of vec2s to iterate over. If 0 iterates over entire array
* @param {Function} fn Function to call for each vector in the array
* @param {Object} [arg] additional argument to pass to fn
* @returns {Array} a
* @function
*/
vec4.forEach = (function() {
var vec = vec4.create();
return function(a, stride, offset, count, fn, arg) {
var i, l;
if(!stride) {
stride = 4;
}
if(!offset) {
offset = 0;
}
if(count) {
l = Math.min((count * stride) + offset, a.length);
} else {
l = a.length;
}
for(i = offset; i < l; i += stride) {
vec[0] = a[i]; vec[1] = a[i+1]; vec[2] = a[i+2]; vec[3] = a[i+3];
fn(vec, vec, arg);
a[i] = vec[0]; a[i+1] = vec[1]; a[i+2] = vec[2]; a[i+3] = vec[3];
}
return a;
};
})();
/**
* Returns a string representation of a vector
*
* @param {vec4} vec vector to represent as a string
* @returns {String} string representation of the vector
*/
vec4.str = function (a) {
return 'vec4(' + a[0] + ', ' + a[1] + ', ' + a[2] + ', ' + a[3] + ')';
};
export default vec4;

626
src/globe/beam/glMatrix/quat.js Executable file
View File

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

584
src/globe/beam/glMatrix/vec2.js Executable file
View File

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

776
src/globe/beam/glMatrix/vec3.js Executable file
View File

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

606
src/globe/beam/glMatrix/vec4.js Executable file
View File

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

27
src/globe/beam/index.js Executable file
View File

@@ -0,0 +1,27 @@
export {default as ArrayBuffer} from './ArrayBuffer';
export {default as Program} from './Program';
export {default as Material} from './Material';
export {default as Texture} from './Texture';
export {default as Container} from './Container';
export {default as Mesh} from './Mesh';
export {default as Renderer} from './Renderer';
export {default as Camera} from './Camera';
export {default as Object3d} from './Object3d';
import * as mat2 from "./glMatrix/mat2";
import * as mat2d from "./glMatrix/mat2d";
import * as mat3 from "./glMatrix/mat3";
import * as mat4 from "./glMatrix/mat4";
import * as quat from "./glMatrix/quat";
import * as vec2 from "./glMatrix/vec2";
import * as vec3 from "./glMatrix/vec3";
import * as vec4 from "./glMatrix/vec4";
export {
mat2, mat2d, mat3, mat4,
quat,
vec2, vec3, vec4,
};
export {default as GeometryBuffer} from './GeometryBuffer';
export {default as PlaneGeometryBuffer} from './PlaneGeometryBuffer';
export {default as SphereGeometryBuffer} from './SphereGeometryBuffer';

View File

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

View File

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

View File

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

View File

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

View File

@@ -0,0 +1,62 @@
// simulation
varying vec2 vUv;
uniform sampler2D tPositions;
uniform sampler2D tOrigin;
uniform sampler2D tTarget;
uniform sampler2D tVelocity;
uniform float timer;
uniform float targetSpeed;
uniform vec3 meshPosition;
uniform float width;
uniform float height;
uniform float depth;
void main() {
vec3 pos = texture2D( tPositions, vUv ).xyz;
vec3 velocity = texture2D( tVelocity, vUv ).xyz;
vec3 target = texture2D( tTarget, vUv ).xyz;
pos += velocity;
// if (target.x == 0.
// && target.y == 0.
// && target.z == 0. ) {
// //no target sepcified
// }
// else{
// pos.x += (target.x - pos.x) * targetSpeed;
// pos.y += (target.y - pos.y) * targetSpeed;
// pos.z += (target.z - pos.z) * targetSpeed;
// }
//pos.z += meshPosition.z;
//GROUND
// if (pos.y < 0.0) {
// pos.y = 0.0;
// }
if( pos.y > height * .5) {
pos.y = height * -.5 + 1.;
}
if (pos.y < height * -.5) {
pos.y = height * .5 - 1.;
}
if (pos.x > width * .5) {
pos.x = width * -.5;
}
if (pos.x < width * -.5) {
pos.x = width * .5;
}
gl_FragColor = vec4(pos, 1.0);
}

View File

@@ -0,0 +1,135 @@
// simulation
varying vec2 vUv;
uniform sampler2D tPositions;
uniform sampler2D tOrigin;
uniform sampler2D tTarget;
uniform sampler2D tVelocity;
uniform sampler2D tForce;
uniform float timer;
uniform vec3 collisionMouse;
uniform float forceTarget;
uniform float delta;
uniform int useMouse;
#define M_PI 3.1415926535897932384626433832795
uniform float gravityStrength;
uniform float windStrength;
uniform float targetStrength;
void main() {
float damping = 1.0 - 0.006;
float attractionForce = -10000000.0;
float attractionRadius = 5000.0;
vec3 pos = texture2D( tPositions, vUv ).xyz * 1.0 - 0.5;
vec3 velocity = texture2D( tVelocity, vUv ).xyz* 1.0 - 0.5;
// // //???
// // velocity *= 0.5;
vec3 force = vec3(0.0);
// target
vec3 target = texture2D( tTarget, vUv ).xyz;
if (target.x != 0.
&& target.y != 0.
&& target.z != 0. ) {
float targetDx = pos.x - target.x;
float targetDy = pos.y - target.y;
float targetDz = pos.z - target.z;
float targetRadiusSq = 10.0 * 10.0;
float targetDistSq = (targetDx*targetDx + targetDy*targetDy + targetDz*targetDz);
if (targetDistSq > 0.1) {//avoid shake
vec3 attractionTarget = vec3( target.x, target.y, target.z );
attractionTarget -= pos;
attractionTarget = normalize( attractionTarget );
attractionTarget *= targetDistSq * targetStrength;
force += attractionTarget;
}
}
/**
* COMPUTE FORCE
*/
// if (useMouse == 1) {
// float dx = pos.x - collisionMouse.x;
// float dy = pos.y - collisionMouse.y;
// float dz = pos.z - collisionMouse.z;
// float distSq = (dx*dx + dy*dy + dz*dz);
// float attractionRadiusSq = attractionRadius*attractionRadius;
// if (distSq > 0.000004 && distSq < attractionRadiusSq) {
// float ratio = (1.0 - distSq / attractionRadiusSq); //dist / attractionRadius;
// vec3 attractionBehaviourForce = vec3( collisionMouse.x, collisionMouse.y, collisionMouse.z );
// attractionBehaviourForce -= pos;
// attractionBehaviourForce = normalize( attractionBehaviourForce );
// attractionBehaviourForce *= ratio;
// attractionBehaviourForce *= attractionForce;
// force += attractionBehaviourForce;
// }
// }
//GRAVITY
vec3 gravityForce = vec3(0., -1., 0.);
gravityForce *= gravityStrength;
force += gravityForce;
//wind
vec3 windForce = vec3(1., 0., 0.);
windForce *= windStrength;
force += windForce;
/**
* COMPUTE VELOCITY [EULER INTEGRATE]
*/
vec3 oldVelocity = vec3( velocity.x, velocity.y, velocity.z );
vec3 newForce = force * timer;
vec3 newVelocity = velocity + newForce;
newVelocity *= damping;
oldVelocity += newVelocity;
oldVelocity *= 0.5 * timer;
// particle.old.p.copy(particle.p);
// particle.old.v.copy(particle.v);
// particle.a.multiplyScalar(1 / particle.mass);
// particle.v.add(particle.a.multiplyScalar(time));
// particle.p.add(particle.old.v.multiplyScalar(time));
// if (damping){
// particle.v.multiplyScalar(damping);
// }
// particle.a.clear();
gl_FragColor = vec4( oldVelocity, 1.0 );
}

View File

@@ -0,0 +1,38 @@
attribute vec2 uv;
attribute vec3 color;
attribute vec3 position;
attribute float vertexIndex;
attribute float particleIndex;
uniform mat4 uMVMatrix;
uniform mat4 uPMatrix;
// uniform float pointSize;
varying vec2 vUv;
void main() {
vUv = uv;
vec3 newPosition = position;
if (vertexIndex == 0.0) {
newPosition += vec3(-1.,1.,0.);
}
else if (vertexIndex == 1.0) {
newPosition += vec3(1.,1.,0.);
}
else if (vertexIndex == 2.0) {
newPosition += vec3(-1.,-1.,0.);
}
else if (vertexIndex == 3.0) {
newPosition += vec3(1.,-1.,0.);
}
newPosition *= 10.;
gl_Position = uPMatrix * uMVMatrix * vec4( newPosition, 1.0 );
}

20
src/globe/beam/uniformTypes.js Executable file
View File

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

View File

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

View File

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

31
src/globe/beam/utils/uuid.js Executable file
View File

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

3
src/globe/beam/utils/warn.js Executable file
View File

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

View File

@@ -0,0 +1,396 @@
/*
Copyright (c) 2013 Aaron Boman and aaronboman.com
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
'use strict';
var OBJ = {};
/**
* The main Mesh class. The constructor will parse through the OBJ file data
* and collect the vertex, vertex normal, texture, and face information. This
* information can then be used later on when creating your VBOs. See
* OBJ.initMeshBuffers for an example of how to use the newly created Mesh
*
* @class Mesh
* @constructor
*
* @param {String} objectData a string representation of an OBJ file with newlines preserved.
*/
OBJ.Mesh = function (objectData) {
/*
The OBJ file format does a sort of compression when saving a model in a
program like Blender. There are at least 3 sections (4 including textures)
within the file. Each line in a section begins with the same string:
* 'v': indicates vertex section
* 'vn': indicates vertex normal section
* 'f': indicates the faces section
* 'vt': indicates vertex texture section (if textures were used on the model)
Each of the above sections (except for the faces section) is a list/set of
unique vertices.
Each line of the faces section contains a list of
(vertex, [texture], normal) groups
Some examples:
// the texture index is optional, both formats are possible for models
// without a texture applied
f 1/25 18/46 12/31
f 1//25 18//46 12//31
// A 3 vertex face with texture indices
f 16/92/11 14/101/22 1/69/1
// A 4 vertex face
f 16/92/11 40/109/40 38/114/38 14/101/22
The first two lines are examples of a 3 vertex face without a texture applied.
The second is an example of a 3 vertex face with a texture applied.
The third is an example of a 4 vertex face. Note: a face can contain N
number of vertices.
Each number that appears in one of the groups is a 1-based index
corresponding to an item from the other sections (meaning that indexing
starts at one and *not* zero).
For example:
`f 16/92/11` is saying to
- take the 16th element from the [v] vertex array
- take the 92nd element from the [vt] texture array
- take the 11th element from the [vn] normal array
and together they make a unique vertex.
Using all 3+ unique Vertices from the face line will produce a polygon.
Now, you could just go through the OBJ file and create a new vertex for
each face line and WebGL will draw what appears to be the same model.
However, vertices will be overlapped and duplicated all over the place.
Consider a cube in 3D space centered about the origin and each side is
2 units long. The front face (with the positive Z-axis pointing towards
you) would have a Top Right vertex (looking orthogonal to its normal)
mapped at (1,1,1) The right face would have a Top Left vertex (looking
orthogonal to its normal) at (1,1,1) and the top face would have a Bottom
Right vertex (looking orthogonal to its normal) at (1,1,1). Each face
has a vertex at the same coordinates, however, three distinct vertices
will be drawn at the same spot.
To solve the issue of duplicate Vertices (the `(vertex, [texture], normal)`
groups), while iterating through the face lines, when a group is encountered
the whole group string ('16/92/11') is checked to see if it exists in the
packed.hashindices object, and if it doesn't, the indices it specifies
are used to look up each attribute in the corresponding attribute arrays
already created. The values are then copied to the corresponding unpacked
array (flattened to play nice with WebGL's ELEMENT_ARRAY_BUFFER indexing),
the group string is added to the hashindices set and the current unpacked
index is used as this hashindices value so that the group of elements can
be reused. The unpacked index is incremented. If the group string already
exists in the hashindices object, its corresponding value is the index of
that group and is appended to the unpacked indices array.
*/
var verts = [], vertNormals = [], textures = [], unpacked = {};
// unpacking stuff
unpacked.verts = [];
unpacked.norms = [];
unpacked.textures = [];
unpacked.hashindices = {};
unpacked.indices = [];
unpacked.index = 0;
// array of lines separated by the newline
var lines = objectData.split('\n');
var VERTEX_RE = /^v\s/;
var NORMAL_RE = /^vn\s/;
var TEXTURE_RE = /^vt\s/;
var FACE_RE = /^f\s/;
var WHITESPACE_RE = /\s+/;
for (var i = 0; i < lines.length; i++) {
var line = lines[i].trim();
var elements = line.split(WHITESPACE_RE);
elements.shift();
if (VERTEX_RE.test(line)) {
// if this is a vertex
verts.push.apply(verts, elements);
} else if (NORMAL_RE.test(line)) {
// if this is a vertex normal
vertNormals.push.apply(vertNormals, elements);
} else if (TEXTURE_RE.test(line)) {
// if this is a texture
textures.push.apply(textures, elements);
} else if (FACE_RE.test(line)) {
// if this is a face
/*
split this face into an array of vertex groups
for example:
f 16/92/11 14/101/22 1/69/1
becomes:
['16/92/11', '14/101/22', '1/69/1'];
*/
var quad = false;
for (var j = 0, eleLen = elements.length; j < eleLen; j++){
// Triangulating quads
// quad: 'f v0/t0/vn0 v1/t1/vn1 v2/t2/vn2 v3/t3/vn3/'
// corresponding triangles:
// 'f v0/t0/vn0 v1/t1/vn1 v2/t2/vn2'
// 'f v2/t2/vn2 v3/t3/vn3 v0/t0/vn0'
if(j === 3 && !quad) {
// add v2/t2/vn2 in again before continuing to 3
j = 2;
quad = true;
}
if (elements[j] in unpacked.hashindices) {
unpacked.indices.push(unpacked.hashindices[elements[j]]);
}
else {
//if no slah found in elemnt, it uses another syntax for faces:
if ( !/\//.test(elements[ j ]) ) {
unpacked.indices.push( elements[ j ] );
}
else {
/*
Each element of the face line array is a vertex which has its
attributes delimited by a forward slash. This will separate
each attribute into another array:
'19/92/11'
becomes:
vertex = ['19', '92', '11'];
where
vertex[0] is the vertex index
vertex[1] is the texture index
vertex[2] is the normal index
Think of faces having Vertices which are comprised of the
attributes location (v), texture (vt), and normal (vn).
*/
var vertex = elements[ j ].split( '/' );
/*
The verts, textures, and vertNormals arrays each contain a
flattend array of coordinates.
Because it gets confusing by referring to vertex and then
vertex (both are different in my descriptions) I will explain
what's going on using the vertexNormals array:
vertex[2] will contain the one-based index of the vertexNormals
section (vn). One is subtracted from this index number to play
nice with javascript's zero-based array indexing.
Because vertexNormal is a flattened array of x, y, z values,
simple pointer arithmetic is used to skip to the start of the
vertexNormal, then the offset is added to get the correct
component: +0 is x, +1 is y, +2 is z.
This same process is repeated for verts and textures.
*/
// vertex position
unpacked.verts.push(+verts[(vertex[0] - 1) * 3 + 0]);
unpacked.verts.push(+verts[(vertex[0] - 1) * 3 + 1]);
unpacked.verts.push(+verts[(vertex[0] - 1) * 3 + 2]);
// vertex textures
if (textures.length) {
unpacked.textures.push(+textures[(vertex[1] - 1) * 2 + 0]);
unpacked.textures.push(+textures[(vertex[1] - 1) * 2 + 1]);
}
// vertex normals
unpacked.norms.push(+vertNormals[(vertex[2] - 1) * 3 + 0]);
unpacked.norms.push(+vertNormals[(vertex[2] - 1) * 3 + 1]);
unpacked.norms.push(+vertNormals[(vertex[2] - 1) * 3 + 2]);
// add the newly created vertex to the list of indices
unpacked.hashindices[elements[j]] = unpacked.index;
unpacked.indices.push(unpacked.index);
// increment the counter
unpacked.index += 1;
}
}
if(j === 3 && quad) {
// add v0/t0/vn0 onto the second triangle
unpacked.indices.push( unpacked.hashindices[elements[0]]);
}
}
}
}
this.vertices = unpacked.verts;
this.vertexNormals = unpacked.norms;
this.textures = unpacked.textures;
this.indices = unpacked.indices;
}
var Ajax = function(){
// this is just a helper class to ease ajax calls
var _this = this;
this.xmlhttp = new XMLHttpRequest();
this.get = function(url, callback){
_this.xmlhttp.onreadystatechange = function(){
if(_this.xmlhttp.readyState === 4){
callback(_this.xmlhttp.responseText, _this.xmlhttp.status);
}
};
_this.xmlhttp.open('GET', url, true);
_this.xmlhttp.send();
}
};
/**
* Takes in an object of `mesh_name`, `'/url/to/OBJ/file'` pairs and a callback
* function. Each OBJ file will be ajaxed in and automatically converted to
* an OBJ.Mesh. When all files have successfully downloaded the callback
* function provided will be called and passed in an object containing
* the newly created meshes.
*
* **Note:** In order to use this function as a way to download meshes, a
* webserver of some sort must be used.
*
* @param {Object} nameAndURLs an object where the key is the name of the mesh and the value is the url to that mesh's OBJ file
*
* @param {Function} completionCallback should contain a function that will take one parameter: an object array where the keys will be the unique object name and the value will be a Mesh object
*
* @param {Object} meshes In case other meshes are loaded separately or if a previously declared variable is desired to be used, pass in a (possibly empty) json object of the pattern: { '<mesh_name>': OBJ.Mesh }
*
*/
OBJ.downloadMeshes = function (nameAndURLs, completionCallback, meshes){
// the total number of meshes. this is used to implement "blocking"
var semaphore = Object.keys(nameAndURLs).length;
// if error is true, an alert will given
var error = false;
// this is used to check if all meshes have been downloaded
// if meshes is supplied, then it will be populated, otherwise
// a new object is created. this will be passed into the completionCallback
if(meshes === undefined) meshes = {};
// loop over the mesh_name,url key,value pairs
for(var mesh_name in nameAndURLs){
if(nameAndURLs.hasOwnProperty(mesh_name)){
new Ajax().get(nameAndURLs[mesh_name], (function(name) {
return function (data, status) {
if (status === 200) {
meshes[name] = new OBJ.Mesh(data);
}
else {
error = true;
console.error('An error has occurred and the mesh "' +
nameAndURLs + '" could not be downloaded.');
}
// the request has finished, decrement the counter
semaphore--;
if (semaphore === 0) {
if (error) {
// if an error has occurred, the user is notified here and the
// callback is not called
console.error('An error has occurred and one or meshes has not been ' +
'downloaded. The execution of the script has terminated.');
throw '';
}
// there haven't been any errors in retrieving the meshes
// call the callback
completionCallback(meshes);
}
}
})(mesh_name));
}
}
};
var _buildBuffer = function( gl, type, data, itemSize ){
var buffer = gl.createBuffer();
var arrayView = type === gl.ARRAY_BUFFER ? Float32Array : Uint16Array;
gl.bindBuffer(type, buffer);
gl.bufferData(type, new arrayView(data), gl.STATIC_DRAW);
buffer.itemSize = itemSize;
buffer.numItems = data.length / itemSize;
return buffer;
}
/**
* Takes in the WebGL context and a Mesh, then creates and appends the buffers
* to the mesh object as attributes.
*
* @param {WebGLRenderingContext} gl the `canvas.getContext('webgl')` context instance
* @param {Mesh} mesh a single `OBJ.Mesh` instance
*
* The newly created mesh attributes are:
*
* Attrbute | Description
* :--- | ---
* **normalBuffer** |contains the model&#39;s Vertex Normals
* normalBuffer.itemSize |set to 3 items
* normalBuffer.numItems |the total number of vertex normals
* |
* **textureBuffer** |contains the model&#39;s Texture Coordinates
* textureBuffer.itemSize |set to 2 items
* textureBuffer.numItems |the number of texture coordinates
* |
* **vertexBuffer** |contains the model&#39;s Vertex Position Coordinates (does not include w)
* vertexBuffer.itemSize |set to 3 items
* vertexBuffer.numItems |the total number of vertices
* |
* **indexBuffer** |contains the indices of the faces
* indexBuffer.itemSize |is set to 1
* indexBuffer.numItems |the total number of indices
*
* A simple example (a lot of steps are missing, so don't copy and paste):
*
* var gl = canvas.getContext('webgl'),
* mesh = OBJ.Mesh(obj_file_data);
* // compile the shaders and create a shader program
* var shaderProgram = gl.createProgram();
* // compilation stuff here
* ...
* // make sure you have vertex, vertex normal, and texture coordinate
* // attributes located in your shaders and attach them to the shader program
* shaderProgram.vertexPositionAttribute = gl.getAttribLocation(shaderProgram, "aVertexPosition");
* gl.enableVertexAttribArray(shaderProgram.vertexPositionAttribute);
*
* shaderProgram.vertexNormalAttribute = gl.getAttribLocation(shaderProgram, "aVertexNormal");
* gl.enableVertexAttribArray(shaderProgram.vertexNormalAttribute);
*
* shaderProgram.textureCoordAttribute = gl.getAttribLocation(shaderProgram, "aTextureCoord");
* gl.enableVertexAttribArray(shaderProgram.textureCoordAttribute);
*
* // create and initialize the vertex, vertex normal, and texture coordinate buffers
* // and save on to the mesh object
* OBJ.initMeshBuffers(gl, mesh);
*
* // now to render the mesh
* gl.bindBuffer(gl.ARRAY_BUFFER, mesh.vertexBuffer);
* gl.vertexAttribPointer(shaderProgram.vertexPositionAttribute, mesh.vertexBuffer.itemSize, gl.FLOAT, false, 0, 0);
*
* gl.bindBuffer(gl.ARRAY_BUFFER, mesh.textureBuffer);
* gl.vertexAttribPointer(shaderProgram.textureCoordAttribute, mesh.textureBuffer.itemSize, gl.FLOAT, false, 0, 0);
*
* gl.bindBuffer(gl.ARRAY_BUFFER, mesh.normalBuffer);
* gl.vertexAttribPointer(shaderProgram.vertexNormalAttribute, mesh.normalBuffer.itemSize, gl.FLOAT, false, 0, 0);
*
* gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, model.mesh.indexBuffer);
* gl.drawElements(gl.TRIANGLES, model.mesh.indexBuffer.numItems, gl.UNSIGNED_SHORT, 0);
*/
OBJ.initMeshBuffers = function( gl, mesh ){
mesh.normalBuffer = _buildBuffer(gl, gl.ARRAY_BUFFER, mesh.vertexNormals, 3);
mesh.textureBuffer = _buildBuffer(gl, gl.ARRAY_BUFFER, mesh.textures, 2);
mesh.vertexBuffer = _buildBuffer(gl, gl.ARRAY_BUFFER, mesh.vertices, 3);
mesh.indexBuffer = _buildBuffer(gl, gl.ELEMENT_ARRAY_BUFFER, mesh.indices, 1);
}
OBJ.deleteMeshBuffers = function( gl, mesh ){
gl.deleteBuffer(mesh.normalBuffer);
gl.deleteBuffer(mesh.textureBuffer);
gl.deleteBuffer(mesh.vertexBuffer);
gl.deleteBuffer(mesh.indexBuffer);
}
export default OBJ;

59
src/globe/globe-fs.glsl Normal file
View File

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

60
src/globe/globe-fs.js Normal file
View File

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

20
src/globe/globe-vs.glsl Normal file
View File

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

22
src/globe/globe-vs.js Normal file
View File

@@ -0,0 +1,22 @@
export default `
precision highp float;
attribute vec3 normal;
attribute vec3 position;
attribute vec2 uv;
uniform mat4 uMVMatrix;
uniform mat4 uMMatrix;
uniform mat4 uPMatrix;
varying vec2 vUv;
varying vec3 vNormal;
varying vec3 vPos;
void main(void) {
vUv = uv;
vNormal = (vec4(normal, 0.) * uMMatrix).rgb;
vPos = (vec4(vPos, 1.) * uMMatrix).rgb;
gl_Position = uPMatrix * uMVMatrix * vec4( position, 1.0 );
}
`

286
src/globe/index.js Normal file
View File

@@ -0,0 +1,286 @@
import { Renderer } from './beam'
import { Camera } from './beam'
import { vec2, vec3, mat4 } from './beam'
import { Container, Mesh, Material, Texture, SphereGeometryBuffer } from './beam'
import settings from './settings'
// Shaders in strings
import GlobeVS from './globe-vs'
import GlobeFS from './globe-fs'
function hexToRgb(hex) {
var result = /^#?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})$/i.exec(hex);
return result ? [
parseInt(result[1], 16) / 255,
parseInt(result[2], 16) / 255,
parseInt(result[3], 16) / 255
] : [0,0,0];
}
function lonLatToVector3(lng, lat) {
var phi = (90-lat)*(Math.PI/180),
theta = (lng+180)*(Math.PI/180),
x = -( Math.sin(phi) * Math.cos(theta) ),
z = Math.sin(phi) * Math.sin(theta),
y = Math.cos(phi);
return [x,y,z];
}
class WebglGlobe {
// Constructor
constructor (options) {
this.options = options;
this.$el = options.el;
this.cities = options.markers
let gl;
let canvas = document.createElement('canvas')
try { gl = canvas.getContext("webgl"); }
catch (x) {
try { gl = canvas.getContext("experimental-webgl"); }
catch (x) { gl = null; }
}
this.supportWebgl = gl !== null;
if (this.supportWebgl) {
this.buildWebglScene()
this.resize()
// this.initPointer()
}
}
// Build
buildWebglScene () {
this.renderer = new Renderer({
alpha: this.alpha,
antialias: this.antialias,
});
this.$el.appendChild(this.renderer.canvas);
this.texture = Texture.fromUrl(this.renderer.gl, this.options.texture)
this.scene = new Container()
this.camera = new Camera({
fov: settings.fov,
near: 1,
far: settings.cameraFar,
type: 'perspective',
orbitControl: true,
firstPerson: false,
lookAt: [0,0,0],
position: [0,0, (3) / 2 / Math.tan(Math.PI * settings.fov / 360)],
});
this.camera.lookAt = vec3.create()
this.inverseViewProjectionMatrix = mat4.create()
this.viewProjectionMatrix = mat4.create()
this.cameraDirection = vec3.create();
this.cameraPosition = vec3.create();
this.globeMesh = new Mesh();
this.globeMesh.material = new Material(this.renderer.gl, {
uniforms: {
tInput: this.texture
},
vertexShader: GlobeVS,
fragmentShader: GlobeFS,
// depthTest: true
})
this.globeMesh.geometry = new SphereGeometryBuffer(this.renderer.gl, {
radius: 1,
widthSegments: 100, heightSegments: 100
})
this.scene.add( this.globeMesh )
this.markers = []
let markers = this.cities
for (let i=0; i<markers.length; i++) {
let markerMesh = new Mesh();
markerMesh.material = new Material(this.renderer.gl, {
blend: true,
uniforms: {
color: hexToRgb( "#FF6C89" ),
alpha: 0,
},
})
markerMesh.geometry = new SphereGeometryBuffer(this.renderer.gl, {
radius: 0.01,
widthSegments: 10, heightSegments: 10
})
let p = lonLatToVector3( markers[i].lng, markers[i].lat )
markerMesh.position[0] = p[0] * 1.
markerMesh.position[1] = p[1] * 1.
markerMesh.position[2] = p[2] * 1.
this.scene.add( markerMesh )
let el = document.createElement('div')
let span = document.createElement('span')
span.innerHTML = markers[i].name
el.appendChild(span)
el.addEventListener('click', ()=>{
alert('click on ' + markers[i].name)
})
el.classList.add('marker')
this.$el.appendChild( el )
this.markers.push({
mesh: markerMesh,
el: el,
position: p,
screenPosition: [0,0]
})
}
}
// Resize method
resize () {
this.width = this.$el.clientWidth;
this.height = this.$el.clientHeight;
settings.resolution[0] = this.width //* settings.devicePixelRatio
settings.resolution[1] = this.height //* settings.devicePixelRatio
if (!this.supportWebgl) {
return
}
this.renderer.setPixelRatio(settings.devicePixelRatio);
this.renderer.resize(settings.resolution[0], settings.resolution[1])
this.camera.aspect = settings.resolution[0] / settings.resolution[1]
this.camera.updateProjectionMatrix()
this.camera.lookAt[0] = 0
this.camera.lookAt[1] = 0
this.camera.lookAt[2] = 0
this.camera.rotation[0] = 0
this.camera.rotation[1] = 0
this.camera.rotation[2] = 0
this.camera.position[0] = 0
this.camera.position[1] = 0
this.camera.position[2] = (3) / 2 / Math.tan(Math.PI * settings.fov / 360)
this.camera.render();
vec3.set(this.cameraPosition, this.camera.worldMatrix[12], this.camera.worldMatrix[13], this.camera.worldMatrix[14]);
vec3.copy(this.cameraDirection, this.camera.lookAt);
vec3.subtract(this.cameraDirection, this.cameraDirection, this.cameraPosition);
vec3.normalize(this.cameraDirection, this.cameraDirection);
mat4.copy(this.viewProjectionMatrix, this.camera.projectionMatrix);
mat4.multiply(this.viewProjectionMatrix, this.viewProjectionMatrix, this.camera.inverseWorldMatrix);
let refPos = vec3.create()
vec3.set(refPos, 0, 1, 0 )
vec3.transformMat4(refPos, refPos, this.viewProjectionMatrix);
let refx = ( (refPos[0] + 1) / 2) * window.innerWidth
let refy = (1. - (refPos[1] + 1) / 2) * window.innerHeight
let dir2 = vec2.create()
vec2.set( dir2, refx, refy )
let center2 = vec2.create()
vec2.set( center2, window.innerWidth/2, window.innerHeight/2 )
let dir2d2 = vec2.clone(dir2, dir2)
vec2.subtract( dir2d2, dir2d2, center2 )
this.circleScreenSize = vec2.length( dir2d2 ) * 1.04
}
// Update
update () {
if (!this.supportWebgl){
return;
}
// this.currPointer[0] += ( this.pointerRatio[0] - this.currPointer[0]) * 0.05
// this.currPointer[1] += ( this.pointerRatio[1] - this.currPointer[1]) * 0.05
// this.globeMesh.rotation[1] = this.currPointer[0]
// this.globeMesh.rotation[2] = this.currPointer[1]
//manually call this as we prevent ithe camera from update between passes
this.camera.update();
vec3.set(this.cameraPosition, this.camera.worldMatrix[12], this.camera.worldMatrix[13], this.camera.worldMatrix[14]);
vec3.copy(this.cameraDirection, this.camera.lookAt);
vec3.subtract(this.cameraDirection, this.cameraDirection, this.cameraPosition);
vec3.normalize(this.cameraDirection, this.cameraDirection);
mat4.copy(this.viewProjectionMatrix, this.camera.projectionMatrix);
mat4.multiply(this.viewProjectionMatrix, this.viewProjectionMatrix, this.camera.inverseWorldMatrix);
mat4.invert(this.inverseViewProjectionMatrix, this.viewProjectionMatrix);
let screenPos = vec3.create()
this.markers.forEach((marker, i)=>{
vec3.set(screenPos, marker.position[0], marker.position[1], marker.position[2] )
vec3.transformMat4(screenPos, screenPos, this.viewProjectionMatrix);
let x = ( (screenPos[0] + 1) / 2) * window.innerWidth
let y = (1. - (screenPos[1] + 1) / 2) * window.innerHeight
let N = vec3.create()
vec3.set( N, marker.position[0], marker.position[1], marker.position[2] )
vec3.normalize( N, N )
let V = vec3.create()
vec3.set( V, marker.position[0], marker.position[1], marker.position[2] )
vec3.subtract( V, V, this.cameraPosition )
vec3.normalize( V, V );
//behind
if ( vec3.dot( V, N ) * -1 < 0) {
let dir = vec2.create()
vec2.set( dir, x, y )
let center = vec2.create()
vec2.set( center, window.innerWidth/2, window.innerHeight/2 )
let dir2d = vec2.clone(dir, dir)
vec2.subtract( dir2d, dir2d, center )
vec2.normalize( dir2d, dir2d );
vec2.scale( dir2d, dir2d, this.circleScreenSize );
vec2.add(dir2d, dir2d, center)
marker.el.style.transform = `translate(${dir2d[0]}px, ${dir2d[1]}px) translateZ(0)`;
marker.el.classList.remove('is-active')
}
else {
//vec3.dot( V, N ) * -1 < 0 ? (1 - vec3.dot( V, N ) / 0.1 ) : 1;//Math.max( 0, vec3.dot( N, V ) );
marker.el.style.transform = `translate(${x}px, ${y}px) translateZ(0)`;
marker.el.classList.add('is-active')
}
// marker.el.style.opacity = 1.
})
this.renderer.clearColor(0,0,0,0)
this.renderer.clear()
this.renderer.render(this.scene, this.camera);
}
// initPointer() {
// this.currPointer = [0,0]
// this.pointer = [0,0]
// this.pointerRatio = [0,0]
// this._onPointerDown = this._onPointerDown.bind(this)
// this._onPointerMove = this._onPointerMove.bind(this)
// this._onPointerUp = this._onPointerUp.bind(this)
// this._handleOrientation = this._handleOrientation.bind(this)
// document.addEventListener(support.pointerdown, this._onPointerDown, false);
// document.addEventListener(support.pointermove, this._onPointerMove, false);
// document.addEventListener(support.pointerup, this._onPointerUp, false);
// window.addEventListener('deviceorientation', this._handleOrientation);
// }
// _handleOrientation(event) {
// this.pointerRatio[0] = (event.gamma) / 25
// this.pointerRatio[1] = (event.beta-45) / 25
// }
// _onPointerDown() {
// this._isPointerDown = true;
// }
// _onPointerUp() {
// this._isPointerDown = false
// }
// _onPointerMove(event) {
// let pe = support.touch && event.type != 'mousemove' ? (event.touches[0] || event.changedTouches[0]) : event;
// this.pointer[0] = pe.pageX;
// this.pointer[1] = pe.pageY;
// this.pointer[1] -= window.pageYOffset || document.documentElement.scrollTop
// this.pointerRatio[0] = (this.pointer[0] / window.innerWidth - .5) * 2
// this.pointerRatio[1] = (this.pointer[1] / window.innerHeight - .5) * 2
// }
}
// window.WebglGlobe = WebglGlobe
export default WebglGlobe

12
src/globe/settings.js Normal file
View File

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

View File

@@ -0,0 +1,47 @@
var support = {};
var tests = {
touch: function () {
return 'ontouchstart' in window || /*|| (navigator.maxTouchPoints > 0)*/navigator.msMaxTouchPoints > 0;
},
//IE10 Pointers
msPointer: function () {
return !!window.navigator.msPointerEnabled;
},
//IE11 Pointers
pointer: function () {
return !!window.navigator.pointerEnabled;
},
pointerdown: function () {
return this.touch() ? 'touchstart' : this.pointer() ? 'pointerdown' : this.msPointer() ? 'MSPointerDown' : 'mousedown';
},
pointerup: function () {
return this.touch() ? 'touchend' : this.pointer() ? 'pointerup' : this.msPointer() ? 'MSPointerUp' : 'mouseup';
},
pointermove: function () {
return this.touch() ? 'touchmove' : this.pointer() ? 'pointermove' : this.msPointer() ? 'MSPointerMove' : 'mousemove';
},
pointerenter: function () {
return this.touch() ? 'touchstart' : this.pointer() ? 'pointerenter' : this.msPointer() ? 'MSPointerEnter' : 'mouseenter';
},
pointerleave: function () {
return this.touch() ? 'touchend' : this.pointer() ? 'pointerleave' : this.msPointer() ? 'MSPointerLeave' : 'mouseleave';
},
pointerover: function () {
return this.touch() ? 'touchstart' : this.pointer() ? 'pointerover' : this.msPointer() ? 'MSPointerOver' : 'mouseover';
},
pointerout: function () {
return this.touch() ? 'touchend' : this.pointer() ? 'pointerout' : this.msPointer() ? 'MSPointerOut' : 'mouseout';
}
};
var featureName;
for (var feature in tests) {
if (tests.hasOwnProperty(feature)) {
featureName = feature;
support[featureName] = tests[feature]();
}
}
export default support