(function webpackUniversalModuleDefinition(root, factory) {
	if(typeof exports === 'object' && typeof module === 'object')
		module.exports = factory();
	else if(typeof define === 'function' && define.amd)
		define([], factory);
	else {
		var a = factory();
		for(var i in a) (typeof exports === 'object' ? exports : root)[i] = a[i];
	}
})(typeof self !== 'undefined' ? self : this, function() {
return /******/ (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] = {
/******/ 			i: moduleId,
/******/ 			l: false,
/******/ 			exports: {}
/******/ 		};
/******/
/******/ 		// Execute the module function
/******/ 		modules[moduleId].call(module.exports, module, module.exports, __webpack_require__);
/******/
/******/ 		// Flag the module as loaded
/******/ 		module.l = 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;
/******/
/******/ 	// define getter function for harmony exports
/******/ 	__webpack_require__.d = function(exports, name, getter) {
/******/ 		if(!__webpack_require__.o(exports, name)) {
/******/ 			Object.defineProperty(exports, name, {
/******/ 				configurable: false,
/******/ 				enumerable: true,
/******/ 				get: getter
/******/ 			});
/******/ 		}
/******/ 	};
/******/
/******/ 	// getDefaultExport function for compatibility with non-harmony modules
/******/ 	__webpack_require__.n = function(module) {
/******/ 		var getter = module && module.__esModule ?
/******/ 			function getDefault() { return module['default']; } :
/******/ 			function getModuleExports() { return module; };
/******/ 		__webpack_require__.d(getter, 'a', getter);
/******/ 		return getter;
/******/ 	};
/******/
/******/ 	// Object.prototype.hasOwnProperty.call
/******/ 	__webpack_require__.o = function(object, property) { return Object.prototype.hasOwnProperty.call(object, property); };
/******/
/******/ 	// __webpack_public_path__
/******/ 	__webpack_require__.p = "";
/******/
/******/ 	// Load entry module and return exports
/******/ 	return __webpack_require__(__webpack_require__.s = 0);
/******/ })
/************************************************************************/
/******/ ([
/* 0 */
/***/ (function(module, exports, __webpack_require__) {

"use strict";


/* global AFRAME, THREE */

if (typeof AFRAME === 'undefined') {
  throw new Error('Component attempted to register before AFRAME was available.');
}

// Configuration for the MutationObserver used to refresh the whitelist.
// Listens for addition/removal of elements and attributes within the scene.
var OBSERVER_CONFIG = {
  childList: true,
  attributes: true,
  subtree: true
};

/**
 * Implement AABB collision detection for entities with a mesh.
 * https://en.wikipedia.org/wiki/Minimum_bounding_box#Axis-aligned_minimum_bounding_box
 *
 * @property {string} objects - Selector of entities to test for collision.
 */
AFRAME.registerComponent('aabb-collider', {
  schema: {
    collideNonVisible: { default: false },
    debug: { default: false },
    enabled: { default: true },
    interval: { default: 80 },
    objects: { default: '' }
  },

  init: function init() {
    this.centerDifferenceVec3 = new THREE.Vector3();
    this.clearedIntersectedEls = [];
    this.closestIntersectedEl = null;
    this.boundingBox = new THREE.Box3();
    this.boxCenter = new THREE.Vector3();
    this.boxHelper = new THREE.BoxHelper();
    this.boxMax = new THREE.Vector3();
    this.boxMin = new THREE.Vector3();
    this.hitClosestClearEventDetail = {};
    this.hitClosestEventDetail = {};
    this.intersectedEls = [];
    this.objectEls = [];
    this.newIntersectedEls = [];
    this.prevCheckTime = undefined;
    this.previousIntersectedEls = [];

    this.setDirty = this.setDirty.bind(this);
    this.observer = new MutationObserver(this.setDirty);
    this.dirty = true;

    this.hitStartEventDetail = { intersectedEls: this.newIntersectedEls };
  },

  play: function play() {
    this.observer.observe(this.el.sceneEl, OBSERVER_CONFIG);
    this.el.sceneEl.addEventListener('object3dset', this.setDirty);
    this.el.sceneEl.addEventListener('object3dremove', this.setDirty);
  },

  remove: function remove() {
    this.observer.disconnect();
    this.el.sceneEl.removeEventListener('object3dset', this.setDirty);
    this.el.sceneEl.removeEventListener('object3dremove', this.setDirty);
  },

  tick: function tick(time) {
    var boundingBox = this.boundingBox;
    var centerDifferenceVec3 = this.centerDifferenceVec3;
    var clearedIntersectedEls = this.clearedIntersectedEls;
    var el = this.el;
    var intersectedEls = this.intersectedEls;
    var newIntersectedEls = this.newIntersectedEls;
    var objectEls = this.objectEls;
    var prevCheckTime = this.prevCheckTime;
    var previousIntersectedEls = this.previousIntersectedEls;

    var closestCenterDifference = void 0;
    var newClosestEl = void 0;
    var i = void 0;

    if (!this.data.enabled) {
      return;
    }

    // Only check for intersection if interval time has passed.
    if (prevCheckTime && time - prevCheckTime < this.data.interval) {
      return;
    }
    // Update check time.
    this.prevCheckTime = time;

    if (this.dirty) {
      this.refreshObjects();
    }

    // Update the bounding box to account for rotations and position changes.
    boundingBox.setFromObject(el.object3D);
    this.boxMin.copy(boundingBox.min);
    this.boxMax.copy(boundingBox.max);
    boundingBox.getCenter(this.boxCenter);

    if (this.data.debug) {
      this.boxHelper.setFromObject(el.object3D);
      if (!this.boxHelper.parent) {
        el.sceneEl.object3D.add(this.boxHelper);
      }
    }

    copyArray(previousIntersectedEls, intersectedEls);

    // Populate intersectedEls array.
    intersectedEls.length = 0;
    for (i = 0; i < objectEls.length; i++) {
      if (objectEls[i] === this.el) {
        continue;
      }

      // Don't collide with non-visible if flag set.
      if (!this.data.collideNonVisible && !objectEls[i].getAttribute('visible')) {
        // Remove box helper if debug flag set and has box helper.
        if (this.data.debug) {
          var boxHelper = objectEls[i].object3D.boxHelper;
          if (boxHelper) {
            el.sceneEl.object3D.remove(boxHelper);
            objectEls[i].object3D.boxHelper = null;
          }
        }
        continue;
      }

      // Check for interection.
      if (this.isIntersecting(objectEls[i])) {
        intersectedEls.push(objectEls[i]);
      }
    }

    // Get newly intersected entities.
    newIntersectedEls.length = 0;
    for (i = 0; i < intersectedEls.length; i++) {
      if (previousIntersectedEls.indexOf(intersectedEls[i]) === -1) {
        newIntersectedEls.push(intersectedEls[i]);
      }
    }

    // Emit cleared events on no longer intersected entities.
    clearedIntersectedEls.length = 0;
    for (i = 0; i < previousIntersectedEls.length; i++) {
      if (intersectedEls.indexOf(previousIntersectedEls[i]) !== -1) {
        continue;
      }
      if (!previousIntersectedEls[i].hasAttribute('aabb-collider')) {
        previousIntersectedEls[i].emit('hitend');
      }
      clearedIntersectedEls.push(previousIntersectedEls[i]);
    }

    // Emit events on intersected entities. Do this after the cleared events.
    for (i = 0; i < newIntersectedEls.length; i++) {
      if (newIntersectedEls[i] === this.el) {
        continue;
      }
      if (newIntersectedEls[i].hasAttribute('aabb-collider')) {
        continue;
      }
      newIntersectedEls[i].emit('hitstart');
    }

    // Calculate closest intersected entity based on centers.
    for (i = 0; i < intersectedEls.length; i++) {
      if (intersectedEls[i] === this.el) {
        continue;
      }
      centerDifferenceVec3.copy(intersectedEls[i].object3D.boundingBoxCenter).sub(this.boxCenter);
      if (closestCenterDifference === undefined || centerDifferenceVec3.length() < closestCenterDifference) {
        closestCenterDifference = centerDifferenceVec3.length();
        newClosestEl = intersectedEls[i];
      }
    }

    // Emit events for the new closest entity and the old closest entity.
    if (!intersectedEls.length && this.closestIntersectedEl) {
      // No intersected entities, clear any closest entity.
      this.hitClosestClearEventDetail.el = this.closestIntersectedEl;
      this.closestIntersectedEl.emit('hitclosestclear');
      this.closestIntersectedEl = null;
      el.emit('hitclosestclear', this.hitClosestClearEventDetail);
    } else if (newClosestEl !== this.closestIntersectedEl) {
      // Clear the previous closest entity.
      if (this.closestIntersectedEl) {
        this.hitClosestClearEventDetail.el = this.closestIntersectedEl;
        this.closestIntersectedEl.emit('hitclosestclear', this.hitClosestClearEventDetail);
      }
      if (newClosestEl) {
        // Emit for the new closest entity.
        newClosestEl.emit('hitclosest');
        this.closestIntersectedEl = newClosestEl;
        this.hitClosestEventDetail.el = newClosestEl;
        el.emit('hitclosest', this.hitClosestEventDetail);
      }
    }

    if (clearedIntersectedEls.length) {
      el.emit('hitend');
    }

    if (newIntersectedEls.length) {
      el.emit('hitstart', this.hitStartEventDetail);
    }
  },

  /**
   * AABB collision detection.
   * 3D version of https://www.youtube.com/watch?v=ghqD3e37R7E
   */
  isIntersecting: function () {
    var boundingBox = new THREE.Box3();

    return function (el) {
      var box = void 0;

      // Dynamic, recalculate each tick.
      if (el.dataset.aabbColliderDynamic) {
        // Box.
        boundingBox.setFromObject(el.object3D);
        box = boundingBox;
        // Center.
        el.object3D.boundingBoxCenter = el.object3D.boundingBoxCenter || new THREE.Vector3();
        box.getCenter(el.object3D.boundingBoxCenter);
      }

      // Static, reuse box and centers.
      if (!el.dataset.aabbColliderDynamic) {
        if (!el.object3D.aabbBox) {
          // Box.
          el.object3D.aabbBox = new THREE.Box3().setFromObject(el.object3D);
          // Center.
          el.object3D.boundingBoxCenter = new THREE.Vector3();
          el.object3D.aabbBox.getCenter(el.object3D.boundingBoxCenter);
        }
        box = el.object3D.aabbBox;
      }

      if (this.data.debug) {
        if (!el.object3D.boxHelper) {
          el.object3D.boxHelper = new THREE.BoxHelper(el.object3D, new THREE.Color(Math.random(), Math.random(), Math.random()));
          el.sceneEl.object3D.add(el.object3D.boxHelper);
        }
        el.object3D.boxHelper.setFromObject(el.object3D);
      }

      var boxMin = box.min;
      var boxMax = box.max;
      return this.boxMin.x <= boxMax.x && this.boxMax.x >= boxMin.x && this.boxMin.y <= boxMax.y && this.boxMax.y >= boxMin.y && this.boxMin.z <= boxMax.z && this.boxMax.z >= boxMin.z;
    };
  }(),

  /**
   * Mark the object list as dirty, to be refreshed before next raycast.
   */
  setDirty: function setDirty() {
    this.dirty = true;
  },

  /**
   * Update list of objects to test for intersection.
   */
  refreshObjects: function refreshObjects() {
    var data = this.data;
    // If objects not defined, intersect with everything.
    this.objectEls = data.objects ? this.el.sceneEl.querySelectorAll(data.objects) : this.el.sceneEl.children;
    this.dirty = false;
  }
});

function copyArray(dest, source) {
  dest.length = 0;
  for (var i = 0; i < source.length; i++) {
    dest[i] = source[i];
  }
}

/***/ })
/******/ ]);
});