| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609 | 
							- /******/ (function(modules) { // webpackBootstrap
 
- /******/ 	// The module cache
 
- /******/ 	var installedModules = {};
 
- /******/ 	// The require function
 
- /******/ 	function __webpack_require__(moduleId) {
 
- /******/ 		// Check if module is in cache
 
- /******/ 		if(installedModules[moduleId])
 
- /******/ 			return installedModules[moduleId].exports;
 
- /******/ 		// Create a new module (and put it into the cache)
 
- /******/ 		var module = installedModules[moduleId] = {
 
- /******/ 			exports: {},
 
- /******/ 			id: moduleId,
 
- /******/ 			loaded: false
 
- /******/ 		};
 
- /******/ 		// Execute the module function
 
- /******/ 		modules[moduleId].call(module.exports, module, module.exports, __webpack_require__);
 
- /******/ 		// Flag the module as loaded
 
- /******/ 		module.loaded = true;
 
- /******/ 		// Return the exports of the module
 
- /******/ 		return module.exports;
 
- /******/ 	}
 
- /******/ 	// expose the modules object (__webpack_modules__)
 
- /******/ 	__webpack_require__.m = modules;
 
- /******/ 	// expose the module cache
 
- /******/ 	__webpack_require__.c = installedModules;
 
- /******/ 	// __webpack_public_path__
 
- /******/ 	__webpack_require__.p = "";
 
- /******/ 	// Load entry module and return exports
 
- /******/ 	return __webpack_require__(0);
 
- /******/ })
 
- /************************************************************************/
 
- /******/ ([
 
- /* 0 */
 
- /***/ (function(module, exports, __webpack_require__) {
 
- 	/* global THREE, AFRAME, Element  */
 
- 	var cylinderTexture = __webpack_require__(1);
 
- 	var parabolicCurve = __webpack_require__(2);
 
- 	var RayCurve = __webpack_require__(3);
 
- 	if (typeof AFRAME === 'undefined') {
 
- 	  throw new Error('Component attempted to register before AFRAME was available.');
 
- 	}
 
- 	if (!Element.prototype.matches) {
 
- 	  Element.prototype.matches =
 
- 	    Element.prototype.matchesSelector ||
 
- 	    Element.prototype.mozMatchesSelector ||
 
- 	    Element.prototype.msMatchesSelector ||
 
- 	    Element.prototype.oMatchesSelector ||
 
- 	    Element.prototype.webkitMatchesSelector ||
 
- 	    function (s) {
 
- 	      var matches = (this.document || this.ownerDocument).querySelectorAll(s);
 
- 	      var i = matches.length;
 
- 	      while (--i >= 0 && matches.item(i) !== this) { /* no-op */ }
 
- 	      return i > -1;
 
- 	    };
 
- 	}
 
- 	AFRAME.registerComponent('teleport-controls', {
 
- 	  schema: {
 
- 	    type: {default: 'parabolic', oneOf: ['parabolic', 'line']},
 
- 	    button: {default: 'trackpad', oneOf: ['trackpad', 'trigger', 'grip', 'menu']},
 
- 	    startEvents: {type: 'array'},
 
- 	    endEvents: {type: 'array'},
 
- 	    collisionEntities: {default: ''},
 
- 	    hitEntity: {type: 'selector'},
 
- 	    cameraRig: {type: 'selector'},
 
- 	    teleportOrigin: {type: 'selector'},
 
- 	    hitCylinderColor: {type: 'color', default: '#99ff99'},
 
- 	    hitCylinderRadius: {default: 0.25, min: 0},
 
- 	    hitCylinderHeight: {default: 0.3, min: 0},
 
- 	    interval: {default: 0},
 
- 	    maxLength: {default: 10, min: 0, if: {type: ['line']}},
 
- 	    curveNumberPoints: {default: 30, min: 2, if: {type: ['parabolic']}},
 
- 	    curveLineWidth: {default: 0.025},
 
- 	    curveHitColor: {type: 'color', default: '#99ff99'},
 
- 	    curveMissColor: {type: 'color', default: '#ff0000'},
 
- 	    curveShootingSpeed: {default: 5, min: 0, if: {type: ['parabolic']}},
 
- 	    defaultPlaneSize: { default: 100 },
 
- 	    landingNormal: {type: 'vec3', default: '0 1 0'},
 
- 	    landingMaxAngle: {default: '45', min: 0, max: 360},
 
- 	    drawIncrementally: {default: false},
 
- 	    incrementalDrawMs: {default: 700},
 
- 	    missOpacity: {default: 1.0},
 
- 	    hitOpacity: {default: 1.0}
 
- 	  },
 
- 	  init: function () {
 
- 	    var data = this.data;
 
- 	    var el = this.el;
 
- 	    var teleportEntity;
 
- 	    var i;
 
- 	    this.active = false;
 
- 	    this.obj = el.object3D;
 
- 	    this.hitPoint = new THREE.Vector3();
 
- 	    this.rigWorldPosition = new THREE.Vector3();
 
- 	    this.newRigWorldPosition = new THREE.Vector3();
 
- 	    this.teleportEventDetail = {
 
- 	      oldPosition: this.rigWorldPosition,
 
- 	      newPosition: this.newRigWorldPosition,
 
- 	      hitPoint: this.hitPoint
 
- 	    };
 
- 	    this.hit = false;
 
- 	    this.prevCheckTime = undefined;
 
- 	    this.prevHitHeight = 0;
 
- 	    this.referenceNormal = new THREE.Vector3();
 
- 	    this.curveMissColor = new THREE.Color();
 
- 	    this.curveHitColor = new THREE.Color();
 
- 	    this.raycaster = new THREE.Raycaster();
 
- 	    this.defaultPlane = createDefaultPlane(this.data.defaultPlaneSize);
 
- 	    this.defaultCollisionMeshes = [this.defaultPlane];
 
- 	    teleportEntity = this.teleportEntity = document.createElement('a-entity');
 
- 	    teleportEntity.classList.add('teleportRay');
 
- 	    teleportEntity.setAttribute('visible', false);
 
- 	    el.sceneEl.appendChild(this.teleportEntity);
 
- 	    this.onButtonDown = this.onButtonDown.bind(this);
 
- 	    this.onButtonUp = this.onButtonUp.bind(this);
 
- 	    if (this.data.startEvents.length && this.data.endEvents.length) {
 
- 	      for (i = 0; i < this.data.startEvents.length; i++) {
 
- 	        el.addEventListener(this.data.startEvents[i], this.onButtonDown);
 
- 	      }
 
- 	      for (i = 0; i < this.data.endEvents.length; i++) {
 
- 	        el.addEventListener(this.data.endEvents[i], this.onButtonUp);
 
- 	      }
 
- 	    } else {
 
- 	      el.addEventListener(data.button + 'down', this.onButtonDown);
 
- 	      el.addEventListener(data.button + 'up', this.onButtonUp);
 
- 	    }
 
- 	    this.queryCollisionEntities();
 
- 	  },
 
- 	  update: function (oldData) {
 
- 	    var data = this.data;
 
- 	    var diff = AFRAME.utils.diff(data, oldData);
 
- 	    // Update normal.
 
- 	    this.referenceNormal.copy(data.landingNormal);
 
- 	    // Update colors.
 
- 	    this.curveMissColor.set(data.curveMissColor);
 
- 	    this.curveHitColor.set(data.curveHitColor);
 
- 	    // Create or update line mesh.
 
- 	    if (!this.line ||
 
- 	        'curveLineWidth' in diff || 'curveNumberPoints' in diff || 'type' in diff) {
 
- 	      this.line = createLine(data);
 
- 	      this.line.material.opacity = this.data.hitOpacity;
 
- 	      this.line.material.transparent = this.data.hitOpacity < 1;
 
- 	      this.numActivePoints = data.curveNumberPoints;
 
- 	      this.teleportEntity.setObject3D('mesh', this.line.mesh);
 
- 	    }
 
- 	    // Create or update hit entity.
 
- 	    if (data.hitEntity) {
 
- 	      this.hitEntity = data.hitEntity;
 
- 	    } else if (!this.hitEntity || 'hitCylinderColor' in diff || 'hitCylinderHeight' in diff ||
 
- 	               'hitCylinderRadius' in diff) {
 
- 	      // Remove previous entity, create new entity (could be more performant).
 
- 	      if (this.hitEntity) { this.hitEntity.parentNode.removeChild(this.hitEntity); }
 
- 	      this.hitEntity = createHitEntity(data);
 
- 	      this.el.sceneEl.appendChild(this.hitEntity);
 
- 	    }
 
- 	    this.hitEntity.setAttribute('visible', false);
 
- 	    if ('collisionEntities' in diff) { this.queryCollisionEntities(); }
 
- 	  },
 
- 	  remove: function () {
 
- 	    var el = this.el;
 
- 	    var hitEntity = this.hitEntity;
 
- 	    var teleportEntity = this.teleportEntity;
 
- 	    if (hitEntity) { hitEntity.parentNode.removeChild(hitEntity); }
 
- 	    if (teleportEntity) { teleportEntity.parentNode.removeChild(teleportEntity); }
 
- 	    el.sceneEl.removeEventListener('child-attached', this.childAttachHandler);
 
- 	    el.sceneEl.removeEventListener('child-detached', this.childDetachHandler);
 
- 	  },
 
- 	  tick: (function () {
 
- 	    var p0 = new THREE.Vector3();
 
- 	    var v0 = new THREE.Vector3();
 
- 	    var g = -9.8;
 
- 	    var a = new THREE.Vector3(0, g, 0);
 
- 	    var next = new THREE.Vector3();
 
- 	    var last = new THREE.Vector3();
 
- 	    var quaternion = new THREE.Quaternion();
 
- 	    var translation = new THREE.Vector3();
 
- 	    var scale = new THREE.Vector3();
 
- 	    var shootAngle = new THREE.Vector3();
 
- 	    var lastNext = new THREE.Vector3();
 
- 	    var auxDirection = new THREE.Vector3();
 
- 	    var timeSinceDrawStart = 0;
 
- 	    return function (time, delta) {
 
- 	      if (!this.active) { return; }
 
- 	      if (this.data.drawIncrementally && this.redrawLine){
 
- 	        this.redrawLine = false;
 
- 	        timeSinceDrawStart = 0;
 
- 	      }
 
- 	      timeSinceDrawStart += delta;
 
- 	      this.numActivePoints = this.data.curveNumberPoints*timeSinceDrawStart/this.data.incrementalDrawMs;
 
- 	      if (this.numActivePoints > this.data.curveNumberPoints){
 
- 	        this.numActivePoints = this.data.curveNumberPoints;
 
- 	      }
 
- 	      // Only check for intersection if interval time has passed.
 
- 	      if (this.prevCheckTime && (time - this.prevCheckTime < this.data.interval)) { return; }
 
- 	      // Update check time.
 
- 	      this.prevCheckTime = time;
 
- 	      var matrixWorld = this.obj.matrixWorld;
 
- 	      matrixWorld.decompose(translation, quaternion, scale);
 
- 	      var direction = shootAngle.set(0, 0, -1)
 
- 	        .applyQuaternion(quaternion).normalize();
 
- 	      this.line.setDirection(auxDirection.copy(direction));
 
- 	      this.obj.getWorldPosition(p0);
 
- 	      last.copy(p0);
 
- 	      // Set default status as non-hit
 
- 	      this.teleportEntity.setAttribute('visible', true);
 
- 	      this.line.material.color.set(this.curveMissColor);
 
- 	      this.line.material.opacity = this.data.missOpacity;
 
- 	      this.line.material.transparent = this.data.missOpacity < 1;
 
- 	      this.hitEntity.setAttribute('visible', false);
 
- 	      this.hit = false;
 
- 	      if (this.data.type === 'parabolic') {
 
- 	        v0.copy(direction).multiplyScalar(this.data.curveShootingSpeed);
 
- 	        this.lastDrawnIndex = 0;
 
- 	        const numPoints = this.data.drawIncrementally ? this.numActivePoints : this.line.numPoints;
 
- 	        for (var i = 0; i < numPoints+1; i++) {
 
- 	          var t;
 
- 	          if (i == Math.floor(numPoints+1)){
 
- 	            t =  numPoints / (this.line.numPoints - 1);
 
- 	          }
 
- 	          else {
 
- 	            t = i / (this.line.numPoints - 1);
 
- 	          }
 
- 	          parabolicCurve(p0, v0, a, t, next);
 
- 	          // Update the raycaster with the length of the current segment last->next
 
- 	          var dirLastNext = lastNext.copy(next).sub(last).normalize();
 
- 	          this.raycaster.far = dirLastNext.length();
 
- 	          this.raycaster.set(last, dirLastNext);
 
- 	          this.lastDrawnPoint = next;
 
- 	          this.lastDrawnIndex = i;
 
- 	          if (this.checkMeshCollisions(i, next)) { break; }
 
- 	          last.copy(next);
 
- 	        }
 
- 	        for (var j = this.lastDrawnIndex+1; j < this.line.numPoints; j++) {
 
- 	          this.line.setPoint(j, this.lastDrawnPoint);
 
- 	        }
 
- 	      } else if (this.data.type === 'line') {
 
- 	        next.copy(last).add(auxDirection.copy(direction).multiplyScalar(this.data.maxLength));
 
- 	        this.raycaster.far = this.data.maxLength;
 
- 	        this.raycaster.set(p0, direction);
 
- 	        this.line.setPoint(0, p0);
 
- 	        this.checkMeshCollisions(1, next);
 
- 	      }
 
- 	    };
 
- 	  })(),
 
- 	  /**
 
- 	   * Run `querySelectorAll` for `collisionEntities` and maintain it with `child-attached`
 
- 	   * and `child-detached` events.
 
- 	   */
 
- 	  queryCollisionEntities: function () {
 
- 	    var collisionEntities;
 
- 	    var data = this.data;
 
- 	    var el = this.el;
 
- 	    if (!data.collisionEntities) {
 
- 	      this.collisionEntities = [];
 
- 	      return;
 
- 	    }
 
- 	    collisionEntities = [].slice.call(el.sceneEl.querySelectorAll(data.collisionEntities));
 
- 	    this.collisionEntities = collisionEntities;
 
- 	    // Update entity list on attach.
 
- 	    this.childAttachHandler = function childAttachHandler (evt) {
 
- 	      if (!evt.detail.el.matches(data.collisionEntities)) { return; }
 
- 	      collisionEntities.push(evt.detail.el);
 
- 	    };
 
- 	    el.sceneEl.addEventListener('child-attached', this.childAttachHandler);
 
- 	    // Update entity list on detach.
 
- 	    this.childDetachHandler = function childDetachHandler (evt) {
 
- 	      var index;
 
- 	      if (!evt.detail.el.matches(data.collisionEntities)) { return; }
 
- 	      index = collisionEntities.indexOf(evt.detail.el);
 
- 	      if (index === -1) { return; }
 
- 	      collisionEntities.splice(index, 1);
 
- 	    };
 
- 	    el.sceneEl.addEventListener('child-detached', this.childDetachHandler);
 
- 	  },
 
- 	  onButtonDown: function () {
 
- 	    this.active = true;
 
- 	    this.redrawLine = true;
 
- 	  },
 
- 	  /**
 
- 	   * Jump!
 
- 	   */
 
- 	  onButtonUp: (function () {
 
- 	    const teleportOriginWorldPosition = new THREE.Vector3();
 
- 	    const newRigLocalPosition = new THREE.Vector3();
 
- 	    const newHandPosition = [new THREE.Vector3(), new THREE.Vector3()]; // Left and right
 
- 	    const handPosition = new THREE.Vector3();
 
- 	    return function (evt) {
 
- 	      if (!this.active) { return; }
 
- 	      // Hide the hit point and the curve
 
- 	      this.active = false;
 
- 	      this.hitEntity.setAttribute('visible', false);
 
- 	      this.teleportEntity.setAttribute('visible', false);
 
- 	      if (!this.hit) {
 
- 	        // Button released but not hit point
 
- 	        return;
 
- 	      }
 
- 	      const rig = this.data.cameraRig || this.el.sceneEl.camera.el;
 
- 	      rig.object3D.getWorldPosition(this.rigWorldPosition);
 
- 	      this.newRigWorldPosition.copy(this.hitPoint);
 
- 	      // If a teleportOrigin exists, offset the rig such that the teleportOrigin is above the hitPoint
 
- 	      const teleportOrigin = this.data.teleportOrigin;
 
- 	      if (teleportOrigin) {
 
- 	        teleportOrigin.object3D.getWorldPosition(teleportOriginWorldPosition);
 
- 	        this.newRigWorldPosition.sub(teleportOriginWorldPosition).add(this.rigWorldPosition);
 
- 	      }
 
- 	      // Always keep the rig at the same offset off the ground after teleporting
 
- 	      this.newRigWorldPosition.y = this.rigWorldPosition.y + this.hitPoint.y - this.prevHitHeight;
 
- 	      this.prevHitHeight = this.hitPoint.y;
 
- 	      // Finally update the rigs position
 
- 	      newRigLocalPosition.copy(this.newRigWorldPosition);
 
- 	      if (rig.object3D.parent) {
 
- 	        rig.object3D.parent.worldToLocal(newRigLocalPosition);
 
- 	      }
 
- 	      rig.setAttribute('position', newRigLocalPosition);
 
- 	      // If a rig was not explicitly declared, look for hands and mvoe them proportionally as well
 
- 	      if (!this.data.cameraRig) {
 
- 	        var hands = document.querySelectorAll('a-entity[tracked-controls]');
 
- 	        for (var i = 0; i < hands.length; i++) {
 
- 	          hands[i].object3D.getWorldPosition(handPosition);
 
- 	          // diff = rigWorldPosition - handPosition
 
- 	          // newPos = newRigWorldPosition - diff
 
- 	          newHandPosition[i].copy(this.newRigWorldPosition).sub(this.rigWorldPosition).add(handPosition);
 
- 	          hands[i].setAttribute('position', newHandPosition[i]);
 
- 	        }
 
- 	      }
 
- 	      this.el.emit('teleported', this.teleportEventDetail);
 
- 	    };
 
- 	  })(),
 
- 	  /**
 
- 	   * Check for raycaster intersection.
 
- 	   *
 
- 	   * @param {number} Line fragment point index.
 
- 	   * @param {number} Next line fragment point index.
 
- 	   * @returns {boolean} true if there's an intersection.
 
- 	   */
 
- 	  checkMeshCollisions: function (i, next) {
 
- 	    // @todo We should add a property to define if the collisionEntity is dynamic or static
 
- 	    // If static we should do the map just once, otherwise we're recreating the array in every
 
- 	    // loop when aiming.
 
- 	    var meshes;
 
- 	    if (!this.data.collisionEntities) {
 
- 	      meshes = this.defaultCollisionMeshes;
 
- 	    } else {
 
- 	      meshes = this.collisionEntities.map(function (entity) {
 
- 	        return entity.getObject3D('mesh');
 
- 	      }).filter(function (n) { return n; });
 
- 	      meshes = meshes.length ? meshes : this.defaultCollisionMeshes;
 
- 	    }
 
- 	    var intersects = this.raycaster.intersectObjects(meshes, true);
 
- 	    if (intersects.length > 0 && !this.hit &&
 
- 	        this.isValidNormalsAngle(intersects[0].face.normal)) {
 
- 	      var point = intersects[0].point;
 
- 	      this.line.material.color.set(this.curveHitColor);
 
- 	      this.line.material.opacity = this.data.hitOpacity;
 
- 	      this.line.material.transparent= this.data.hitOpacity < 1;
 
- 	      this.hitEntity.setAttribute('position', point);
 
- 	      this.hitEntity.setAttribute('visible', true);
 
- 	      this.hit = true;
 
- 	      this.hitPoint.copy(intersects[0].point);
 
- 	      // If hit, just fill the rest of the points with the hit point and break the loop
 
- 	      for (var j = i; j < this.line.numPoints; j++) {
 
- 	        this.line.setPoint(j, this.hitPoint);
 
- 	      }
 
- 	      return true;
 
- 	    } else {
 
- 	      this.line.setPoint(i, next);
 
- 	      return false;
 
- 	    }
 
- 	  },
 
- 	  isValidNormalsAngle: function (collisionNormal) {
 
- 	    var angleNormals = this.referenceNormal.angleTo(collisionNormal);
 
- 	    return (THREE.Math.RAD2DEG * angleNormals <= this.data.landingMaxAngle);
 
- 	  },
 
- 	});
 
- 	function createLine (data) {
 
- 	  var numPoints = data.type === 'line' ? 2 : data.curveNumberPoints;
 
- 	  return new RayCurve(numPoints, data.curveLineWidth);
 
- 	}
 
- 	/**
 
- 	 * Create mesh to represent the area of intersection.
 
- 	 * Default to a combination of torus and cylinder.
 
- 	 */
 
- 	function createHitEntity (data) {
 
- 	  var cylinder;
 
- 	  var hitEntity;
 
- 	  var torus;
 
- 	  // Parent.
 
- 	  hitEntity = document.createElement('a-entity');
 
- 	  hitEntity.className = 'hitEntity';
 
- 	  // Torus.
 
- 	  torus = document.createElement('a-entity');
 
- 	  torus.setAttribute('geometry', {
 
- 	    primitive: 'torus',
 
- 	    radius: data.hitCylinderRadius,
 
- 	    radiusTubular: 0.01
 
- 	  });
 
- 	  torus.setAttribute('rotation', {x: 90, y: 0, z: 0});
 
- 	  torus.setAttribute('material', {
 
- 	    shader: 'flat',
 
- 	    color: data.hitCylinderColor,
 
- 	    side: 'double',
 
- 	    depthTest: false
 
- 	  });
 
- 	  hitEntity.appendChild(torus);
 
- 	  // Cylinder.
 
- 	  cylinder = document.createElement('a-entity');
 
- 	  cylinder.setAttribute('position', {x: 0, y: data.hitCylinderHeight / 2, z: 0});
 
- 	  cylinder.setAttribute('geometry', {
 
- 	    primitive: 'cylinder',
 
- 	    segmentsHeight: 1,
 
- 	    radius: data.hitCylinderRadius,
 
- 	    height: data.hitCylinderHeight,
 
- 	    openEnded: true
 
- 	  });
 
- 	  cylinder.setAttribute('material', {
 
- 	    shader: 'flat',
 
- 	    color: data.hitCylinderColor,
 
- 	    side: 'double',
 
- 	    src: cylinderTexture,
 
- 	    transparent: true,
 
- 	    depthTest: false
 
- 	  });
 
- 	  hitEntity.appendChild(cylinder);
 
- 	  return hitEntity;
 
- 	}
 
- 	function createDefaultPlane (size) {
 
- 	  var geometry;
 
- 	  var material;
 
- 	  geometry = new THREE.PlaneBufferGeometry(100, 100);
 
- 	  geometry.rotateX(-Math.PI / 2);
 
- 	  material = new THREE.MeshBasicMaterial({color: 0xffff00});
 
- 	  return new THREE.Mesh(geometry, material);
 
- 	}
 
- /***/ }),
 
- /* 1 */
 
- /***/ (function(module, exports) {
 
- 	module.exports = 'url(data:image/png;base64,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)';
 
- /***/ }),
 
- /* 2 */
 
- /***/ (function(module, exports) {
 
- 	/* global THREE */
 
- 	// Parabolic motion equation, y = p0 + v0*t + 1/2at^2
 
- 	function parabolicCurveScalar (p0, v0, a, t) {
 
- 	  return p0 + v0 * t + 0.5 * a * t * t;
 
- 	}
 
- 	// Parabolic motion equation applied to 3 dimensions
 
- 	function parabolicCurve (p0, v0, a, t, out) {
 
- 	  out.x = parabolicCurveScalar(p0.x, v0.x, a.x, t);
 
- 	  out.y = parabolicCurveScalar(p0.y, v0.y, a.y, t);
 
- 	  out.z = parabolicCurveScalar(p0.z, v0.z, a.z, t);
 
- 	  return out;
 
- 	}
 
- 	module.exports = parabolicCurve;
 
- /***/ }),
 
- /* 3 */
 
- /***/ (function(module, exports) {
 
- 	/* global THREE */
 
- 	var RayCurve = function (numPoints, width) {
 
- 	  this.geometry = new THREE.BufferGeometry();
 
- 	  this.vertices = new Float32Array(numPoints * 3 * 2);
 
- 	  this.uvs = new Float32Array(numPoints * 2 * 2);
 
- 	  this.width = width;
 
- 	  this.geometry.setAttribute('position', new THREE.BufferAttribute(this.vertices, 3).setUsage(THREE.DynamicDrawUsage));
 
- 	  this.material = new THREE.MeshBasicMaterial({
 
- 	    side: THREE.DoubleSide,
 
- 	    color: 0xff0000
 
- 	  });
 
- 	  this.mesh = new THREE.Mesh(this.geometry, this.material);
 
- 	  THREE.BufferGeometryUtils.toTrianglesDrawMode(this.mesh.geometry, THREE.TriangleStripDrawMode);
 
- 	  //this.mesh.drawMode = THREE.TriangleStripDrawMode;
 
- 	  this.mesh.frustumCulled = false;
 
- 	  this.mesh.vertices = this.vertices;
 
- 	  this.direction = new THREE.Vector3();
 
- 	  this.numPoints = numPoints;
 
- 	};
 
- 	RayCurve.prototype = {
 
- 	  setDirection: function (direction) {
 
- 	    var UP = new THREE.Vector3(0, 1, 0);
 
- 	    this.direction
 
- 	      .copy(direction)
 
- 	      .cross(UP)
 
- 	      .normalize()
 
- 	      .multiplyScalar(this.width / 2);
 
- 	  },
 
- 	  setWidth: function (width) {
 
- 	    this.width = width;
 
- 	  },
 
- 	  setPoint: (function () {
 
- 	    var posA = new THREE.Vector3();
 
- 	    var posB = new THREE.Vector3();
 
- 	    return function (i, point) {
 
- 	      posA.copy(point).add(this.direction);
 
- 	      posB.copy(point).sub(this.direction);
 
- 	      var idx = 2 * 3 * i;
 
- 	      this.vertices[idx++] = posA.x;
 
- 	      this.vertices[idx++] = posA.y;
 
- 	      this.vertices[idx++] = posA.z;
 
- 	      this.vertices[idx++] = posB.x;
 
- 	      this.vertices[idx++] = posB.y;
 
- 	      this.vertices[idx++] = posB.z;
 
- 	      this.geometry.attributes.position.needsUpdate = true;
 
- 	    };
 
- 	  })()
 
- 	};
 
- 	module.exports = RayCurve;
 
- /***/ })
 
- /******/ ]);
 
 
  |