diff --git a/dist/aframe-master.js b/dist/aframe-master.js new file mode 100644 index 0000000..e750676 --- /dev/null +++ b/dist/aframe-master.js @@ -0,0 +1,85773 @@ +(function(f){if(typeof exports==="object"&&typeof module!=="undefined"){module.exports=f()}else if(typeof define==="function"&&define.amd){define([],f)}else{var g;if(typeof window!=="undefined"){g=window}else if(typeof global!=="undefined"){g=global}else if(typeof self!=="undefined"){g=self}else{g=this}g.AFRAME = f()}})(function(){var define,module,exports;return (function(){function r(e,n,t){function o(i,f){if(!n[i]){if(!e[i]){var c="function"==typeof require&&require;if(!f&&c)return c(i,!0);if(u)return u(i,!0);var a=new Error("Cannot find module '"+i+"'");throw a.code="MODULE_NOT_FOUND",a}var p=n[i]={exports:{}};e[i][0].call(p.exports,function(r){var n=e[i][1][r];return o(n||r)},p,p.exports,r,e,n,t)}return n[i].exports}for(var u="function"==typeof require&&require,i=0;i 0) { + throw new Error('Invalid string. Length must be a multiple of 4') + } + + // Trim off extra bytes after placeholder bytes are found + // See: https://github.com/beatgammit/base64-js/issues/42 + var validLen = b64.indexOf('=') + if (validLen === -1) validLen = len + + var placeHoldersLen = validLen === len + ? 0 + : 4 - (validLen % 4) + + return [validLen, placeHoldersLen] +} + +// base64 is 4/3 + up to two characters of the original data +function byteLength (b64) { + var lens = getLens(b64) + var validLen = lens[0] + var placeHoldersLen = lens[1] + return ((validLen + placeHoldersLen) * 3 / 4) - placeHoldersLen +} + +function _byteLength (b64, validLen, placeHoldersLen) { + return ((validLen + placeHoldersLen) * 3 / 4) - placeHoldersLen +} + +function toByteArray (b64) { + var tmp + var lens = getLens(b64) + var validLen = lens[0] + var placeHoldersLen = lens[1] + + var arr = new Arr(_byteLength(b64, validLen, placeHoldersLen)) + + var curByte = 0 + + // if there are placeholders, only get up to the last complete 4 chars + var len = placeHoldersLen > 0 + ? validLen - 4 + : validLen + + for (var i = 0; i < len; i += 4) { + tmp = + (revLookup[b64.charCodeAt(i)] << 18) | + (revLookup[b64.charCodeAt(i + 1)] << 12) | + (revLookup[b64.charCodeAt(i + 2)] << 6) | + revLookup[b64.charCodeAt(i + 3)] + arr[curByte++] = (tmp >> 16) & 0xFF + arr[curByte++] = (tmp >> 8) & 0xFF + arr[curByte++] = tmp & 0xFF + } + + if (placeHoldersLen === 2) { + tmp = + (revLookup[b64.charCodeAt(i)] << 2) | + (revLookup[b64.charCodeAt(i + 1)] >> 4) + arr[curByte++] = tmp & 0xFF + } + + if (placeHoldersLen === 1) { + tmp = + (revLookup[b64.charCodeAt(i)] << 10) | + (revLookup[b64.charCodeAt(i + 1)] << 4) | + (revLookup[b64.charCodeAt(i + 2)] >> 2) + arr[curByte++] = (tmp >> 8) & 0xFF + arr[curByte++] = tmp & 0xFF + } + + return arr +} + +function tripletToBase64 (num) { + return lookup[num >> 18 & 0x3F] + + lookup[num >> 12 & 0x3F] + + lookup[num >> 6 & 0x3F] + + lookup[num & 0x3F] +} + +function encodeChunk (uint8, start, end) { + var tmp + var output = [] + for (var i = start; i < end; i += 3) { + tmp = + ((uint8[i] << 16) & 0xFF0000) + + ((uint8[i + 1] << 8) & 0xFF00) + + (uint8[i + 2] & 0xFF) + output.push(tripletToBase64(tmp)) + } + return output.join('') +} + +function fromByteArray (uint8) { + var tmp + var len = uint8.length + var extraBytes = len % 3 // if we have 1 byte left, pad 2 bytes + var parts = [] + var maxChunkLength = 16383 // must be multiple of 3 + + // go through the array every three bytes, we'll deal with trailing stuff later + for (var i = 0, len2 = len - extraBytes; i < len2; i += maxChunkLength) { + parts.push(encodeChunk( + uint8, i, (i + maxChunkLength) > len2 ? len2 : (i + maxChunkLength) + )) + } + + // pad the end with zeros, but make sure to not forget the extra bytes + if (extraBytes === 1) { + tmp = uint8[len - 1] + parts.push( + lookup[tmp >> 2] + + lookup[(tmp << 4) & 0x3F] + + '==' + ) + } else if (extraBytes === 2) { + tmp = (uint8[len - 2] << 8) + uint8[len - 1] + parts.push( + lookup[tmp >> 10] + + lookup[(tmp >> 4) & 0x3F] + + lookup[(tmp << 2) & 0x3F] + + '=' + ) + } + + return parts.join('') +} + +},{}],4:[function(_dereq_,module,exports){ +'use strict'; +// For more information about browser field, check out the browser field at https://github.com/substack/browserify-handbook#browser-field. + +module.exports = { + // Create a tag with optional data attributes + createLink: function(href, attributes) { + var head = document.head || document.getElementsByTagName('head')[0]; + var link = document.createElement('link'); + + link.href = href; + link.rel = 'stylesheet'; + + for (var key in attributes) { + if ( ! attributes.hasOwnProperty(key)) { + continue; + } + var value = attributes[key]; + link.setAttribute('data-' + key, value); + } + + head.appendChild(link); + }, + // Create a - + diff --git a/package.json b/package.json index de1dd9b..10be2e4 100644 --- a/package.json +++ b/package.json @@ -16,8 +16,8 @@ "keywords": [], "author": "Arturo Paracuellos", "devDependencies": { - "aframe-aabb-collider-component": "^3.2.0", "aframe-environment-component": "^2.0.0", + "aframe-event-set-component": "^5.0.0", "aframe-super-hot-loader": "^1.7.0", "aframe-super-hot-html-loader": "^2.1.0", "babel-core": "^6.26.3", diff --git a/src/components/aabb-collider.js b/src/components/aabb-collider.js new file mode 100644 index 0000000..d6e340b --- /dev/null +++ b/src/components/aabb-collider.js @@ -0,0 +1,105 @@ +/* global AFRAME, THREE */ + +/** + * Implement AABB collision detection for entities with a mesh. + * (https://en.wikipedia.org/wiki/Minimum_bounding_box#Axis-aligned_minimum_bounding_box) + * It sets the specified state on the intersected entities. + * + * @property {string} objects - Selector of the entities to test for collision. + * @property {string} state - State to set on collided entities. + * + */ +AFRAME.registerComponent('aabb-collider', { + schema: { + objects: {default: ''}, + state: {default: 'collided'} + }, + + init: function () { + this.els = []; + this.collisions = []; + this.elMax = new THREE.Vector3(); + this.elMin = new THREE.Vector3(); + }, + + /** + * Update list of entities to test for collision. + */ + update: function () { + var data = this.data; + var objectEls; + + // Push entities into list of els to intersect. + if (data.objects) { + objectEls = this.el.sceneEl.querySelectorAll(data.objects); + } else { + // If objects not defined, intersect with everything. + objectEls = this.el.sceneEl.children; + } + // Convert from NodeList to Array + this.els = Array.prototype.slice.call(objectEls); + }, + + tick: (function () { + var boundingBox = new THREE.Box3(); + return function () { + var collisions = []; + var el = this.el; + var mesh = el.getObject3D('mesh'); + var self = this; + // No mesh, no collisions + if (!mesh) { return; } + // Update the bounding box to account for rotations and + // position changes. + updateBoundingBox(); + // Update collisions. + this.els.forEach(intersect); + // Emit events. + collisions.forEach(handleHit); + // No collisions. + if (collisions.length === 0) { self.el.emit('hit', {el: null}); } + // Updated the state of the elements that are not intersected anymore. + this.collisions.filter(function (el) { + return collisions.indexOf(el) === -1; + }).forEach(function removeState (el) { + el.removeState(self.data.state); + el.emit('hitend'); + }); + // Store new collisions + this.collisions = collisions; + + // AABB collision detection + function intersect (el) { + var intersected; + var mesh = el.getObject3D('mesh'); + var elMin; + var elMax; + if (!mesh) { return; } + boundingBox.setFromObject(mesh); + elMin = boundingBox.min; + elMax = boundingBox.max; + // Bounding boxes are always aligned with the world coordinate system. + // The collision test checks for the conditions where cubes intersect. + // It's an extension to 3 dimensions of this approach (with the condition negated) + // https://www.youtube.com/watch?v=ghqD3e37R7E + intersected = (self.elMin.x <= elMax.x && self.elMax.x >= elMin.x) && + (self.elMin.y <= elMax.y && self.elMax.y >= elMin.y) && + (self.elMin.z <= elMax.z && self.elMax.z >= elMin.z); + if (!intersected) { return; } + collisions.push(el); + } + + function handleHit (hitEl) { + hitEl.emit('hit'); + hitEl.addState(self.data.state); + self.el.emit('hit', {el: hitEl}); + } + + function updateBoundingBox () { + boundingBox.setFromObject(mesh); + self.elMin.copy(boundingBox.min); + self.elMax.copy(boundingBox.max); + } + }; + })() +}); diff --git a/src/components/drag-controls.js b/src/components/drag-controls.js deleted file mode 100644 index f7400e5..0000000 --- a/src/components/drag-controls.js +++ /dev/null @@ -1,19 +0,0 @@ -AFRAME.registerComponent('drag-controls', { - schema: {objects: {type: 'string', default: 'a-entity'}}, - - init: function () { - var objects = []; - var el = this.el; - var els; - var dragControls; - els = el.sceneEl.querySelectorAll(this.data.objects); - for (var i = 0; i < els.length; i++) { - console.log(i); - objects.push(els[i].object3D); - } - - el.sceneEl.addEventListener('renderstart', function () { - dragControls = new THREE.DragControls(objects, el.sceneEl.camera, el.sceneEl.renderer.domElement); - }); - } -}); \ No newline at end of file diff --git a/src/home.html b/src/home.html index 7c9035b..9f8cb0a 100644 --- a/src/home.html +++ b/src/home.html @@ -1,4 +1,4 @@ - + - - - + + + + + - - \ No newline at end of file diff --git a/src/index.js b/src/index.js index 5ad2cdc..987a9fc 100644 --- a/src/index.js +++ b/src/index.js @@ -3,11 +3,11 @@ function requireAll (req) { req.keys().forEach(req); } console.time = () => {}; console.timeEnd = () => {}; -require('aframe-environment-component') -require('aframe-aabb-collider-component'); -require('./lib/DragControls.js'); +require('aframe-environment-component'); +require('aframe-event-set-component'); + +require('./components/aabb-collider'); require('./components/grab'); -require('./components/drag-controls'); require('./index.css') diff --git a/src/lib/DragControls.js b/src/lib/DragControls.js deleted file mode 100644 index 1d73868..0000000 --- a/src/lib/DragControls.js +++ /dev/null @@ -1,282 +0,0 @@ -/* - * @author zz85 / https://github.com/zz85 - * @author mrdoob / http://mrdoob.com - * Running this will allow you to drag three.js objects around the screen. - */ - -THREE.DragControls = function ( _objects, _camera, _domElement ) { - - if ( _objects instanceof THREE.Camera ) { - - console.warn( 'THREE.DragControls: Constructor now expects ( objects, camera, domElement )' ); - var temp = _objects; _objects = _camera; _camera = temp; - - } - - var _plane = new THREE.Plane(); - var _raycaster = new THREE.Raycaster(); - - var _mouse = new THREE.Vector2(); - var _offset = new THREE.Vector3(); - var _intersection = new THREE.Vector3(); - - var _selected = null, _hovered = null; - - // - - var scope = this; - - function activate() { - - _domElement.addEventListener( 'mousemove', onDocumentMouseMove, false ); - _domElement.addEventListener( 'mousedown', onDocumentMouseDown, false ); - _domElement.addEventListener( 'mouseup', onDocumentMouseCancel, false ); - _domElement.addEventListener( 'mouseleave', onDocumentMouseCancel, false ); - _domElement.addEventListener( 'touchmove', onDocumentTouchMove, false ); - _domElement.addEventListener( 'touchstart', onDocumentTouchStart, false ); - _domElement.addEventListener( 'touchend', onDocumentTouchEnd, false ); - - } - - function deactivate() { - - _domElement.removeEventListener( 'mousemove', onDocumentMouseMove, false ); - _domElement.removeEventListener( 'mousedown', onDocumentMouseDown, false ); - _domElement.removeEventListener( 'mouseup', onDocumentMouseCancel, false ); - _domElement.removeEventListener( 'mouseleave', onDocumentMouseCancel, false ); - _domElement.removeEventListener( 'touchmove', onDocumentTouchMove, false ); - _domElement.removeEventListener( 'touchstart', onDocumentTouchStart, false ); - _domElement.removeEventListener( 'touchend', onDocumentTouchEnd, false ); - - } - - function dispose() { - - deactivate(); - - } - - function onDocumentMouseMove( event ) { - - event.preventDefault(); - - var rect = _domElement.getBoundingClientRect(); - - _mouse.x = ( ( event.clientX - rect.left ) / rect.width ) * 2 - 1; - _mouse.y = - ( ( event.clientY - rect.top ) / rect.height ) * 2 + 1; - - _raycaster.setFromCamera( _mouse, _camera ); - - if ( _selected && scope.enabled ) { - - if ( _raycaster.ray.intersectPlane( _plane, _intersection ) ) { - - _selected.position.copy( _intersection.sub( _offset ) ); - - } - - scope.dispatchEvent( { type: 'drag', object: _selected } ); - - return; - - } - - _raycaster.setFromCamera( _mouse, _camera ); - - var intersects = _raycaster.intersectObjects( _objects, true ); - - if ( intersects.length > 0 ) { - - var object = intersects[ 0 ].object.parent; - - _plane.setFromNormalAndCoplanarPoint( _camera.getWorldDirection( _plane.normal ), object.position ); - - if ( _hovered !== object ) { - - scope.dispatchEvent( { type: 'hoveron', object: object } ); - - _domElement.style.cursor = 'pointer'; - _hovered = object; - - } - - } else { - - if ( _hovered !== null ) { - - scope.dispatchEvent( { type: 'hoveroff', object: _hovered } ); - - _domElement.style.cursor = 'auto'; - _hovered = null; - - } - - } - - } - - function onDocumentMouseDown( event ) { - - event.preventDefault(); - - _raycaster.setFromCamera( _mouse, _camera ); - - var intersects = _raycaster.intersectObjects( _objects, true ); - - if ( intersects.length > 0 ) { - - _selected = intersects[ 0 ].object.parent; - - if ( _raycaster.ray.intersectPlane( _plane, _intersection ) ) { - - _offset.copy( _intersection ).sub( _selected.position ); - - } - - _domElement.style.cursor = 'move'; - - scope.dispatchEvent( { type: 'dragstart', object: _selected } ); - - } - - - } - - function onDocumentMouseCancel( event ) { - - event.preventDefault(); - - if ( _selected ) { - - scope.dispatchEvent( { type: 'dragend', object: _selected } ); - - _selected = null; - - } - - _domElement.style.cursor = 'auto'; - - } - - function onDocumentTouchMove( event ) { - - event.preventDefault(); - event = event.changedTouches[ 0 ]; - - var rect = _domElement.getBoundingClientRect(); - - _mouse.x = ( ( event.clientX - rect.left ) / rect.width ) * 2 - 1; - _mouse.y = - ( ( event.clientY - rect.top ) / rect.height ) * 2 + 1; - - _raycaster.setFromCamera( _mouse, _camera ); - - if ( _selected && scope.enabled ) { - - if ( _raycaster.ray.intersectPlane( _plane, _intersection ) ) { - - _selected.position.copy( _intersection.sub( _offset ) ); - - } - - scope.dispatchEvent( { type: 'drag', object: _selected } ); - - return; - - } - - } - - function onDocumentTouchStart( event ) { - - event.preventDefault(); - event = event.changedTouches[ 0 ]; - - var rect = _domElement.getBoundingClientRect(); - - _mouse.x = ( ( event.clientX - rect.left ) / rect.width ) * 2 - 1; - _mouse.y = - ( ( event.clientY - rect.top ) / rect.height ) * 2 + 1; - - _raycaster.setFromCamera( _mouse, _camera ); - - var intersects = _raycaster.intersectObjects( _objects, true ); - - if ( intersects.length > 0 ) { - - _selected = intersects[ 0 ].object.parent; - - _plane.setFromNormalAndCoplanarPoint( _camera.getWorldDirection( _plane.normal ), _selected.position ); - - if ( _raycaster.ray.intersectPlane( _plane, _intersection ) ) { - - _offset.copy( _intersection ).sub( _selected.position ); - - } - - _domElement.style.cursor = 'move'; - - scope.dispatchEvent( { type: 'dragstart', object: _selected } ); - - } - - - } - - function onDocumentTouchEnd( event ) { - - event.preventDefault(); - - if ( _selected ) { - - scope.dispatchEvent( { type: 'dragend', object: _selected } ); - - _selected = null; - - } - - _domElement.style.cursor = 'auto'; - - } - - activate(); - - // API - - this.enabled = true; - - this.activate = activate; - this.deactivate = deactivate; - this.dispose = dispose; - - // Backward compatibility - - this.setObjects = function () { - - console.error( 'THREE.DragControls: setObjects() has been removed.' ); - - }; - - this.on = function ( type, listener ) { - - console.warn( 'THREE.DragControls: on() has been deprecated. Use addEventListener() instead.' ); - scope.addEventListener( type, listener ); - - }; - - this.off = function ( type, listener ) { - - console.warn( 'THREE.DragControls: off() has been deprecated. Use removeEventListener() instead.' ); - scope.removeEventListener( type, listener ); - - }; - - this.notify = function ( type ) { - - console.error( 'THREE.DragControls: notify() has been deprecated. Use dispatchEvent() instead.' ); - scope.dispatchEvent( { type: type } ); - - }; - -}; - -THREE.DragControls.prototype = Object.create( THREE.EventDispatcher.prototype ); -THREE.DragControls.prototype.constructor = THREE.DragControls; \ No newline at end of file