diff --git a/physi.js b/physi.js index 9d5b716..fa4a59c 100644 --- a/physi.js +++ b/physi.js @@ -5,7 +5,6 @@ window.Physijs = (function() { _is_simulating = false, _Physijs = Physijs, // used for noConflict method Physijs = {}, // object assigned to window.Physijs - Eventable, // class to provide simple event methods getObjectId, // returns a unique ID for a Physijs mesh object getEulerXYZFromQuaternion, getQuatertionFromEuler, convertWorldPositionToObject, // Converts a world-space position to object-space @@ -31,42 +30,44 @@ window.Physijs = (function() { Physijs.scripts = {}; - Eventable = function() { - this._eventListeners = {}; - }; - Eventable.prototype.addEventListener = function( event_name, callback ) { - if ( !this._eventListeners.hasOwnProperty( event_name ) ) { - this._eventListeners[event_name] = []; + const Eventable = (superclass) => class extends superclass { + + constructor() { + super(...arguments); + this._eventListeners = {}; } - this._eventListeners[event_name].push( callback ); - }; - Eventable.prototype.removeEventListener = function( event_name, callback ) { - var index; - if ( !this._eventListeners.hasOwnProperty( event_name ) ) return false; + addEventListener( event_name, callback ) { + if ( !this._eventListeners.hasOwnProperty( event_name ) ) { + this._eventListeners[event_name] = []; + } + this._eventListeners[event_name].push( callback ); + } - if ( (index = this._eventListeners[event_name].indexOf( callback )) >= 0 ) { - this._eventListeners[event_name].splice( index, 1 ); - return true; + removeEventListener( event_name, callback ) { + var index; + + if ( !this._eventListeners.hasOwnProperty( event_name ) ) return false; + + if ( (index = this._eventListeners[event_name].indexOf( callback )) >= 0 ) { + this._eventListeners[event_name].splice( index, 1 ); + return true; + } + + return false; } - return false; - }; - Eventable.prototype.dispatchEvent = function( event_name ) { - var i, - parameters = Array.prototype.splice.call( arguments, 1 ); + dispatchEvent( event_name ) { + var i, + parameters = Array.prototype.splice.call( arguments, 1 ); - if ( this._eventListeners.hasOwnProperty( event_name ) ) { - for ( i = 0; i < this._eventListeners[event_name].length; i++ ) { - this._eventListeners[event_name][i].apply( this, parameters ); + if ( this._eventListeners.hasOwnProperty( event_name ) ) { + for ( i = 0; i < this._eventListeners[event_name].length; i++ ) { + this._eventListeners[event_name][i].apply( this, parameters ); + } } } }; - Eventable.make = function( obj ) { - obj.prototype.addEventListener = Eventable.prototype.addEventListener; - obj.prototype.removeEventListener = Eventable.prototype.removeEventListener; - obj.prototype.dispatchEvent = Eventable.prototype.dispatchEvent; - }; getObjectId = (function() { var _id = 1; @@ -147,319 +148,316 @@ window.Physijs = (function() { // Constraints - Physijs.PointConstraint = function( objecta, objectb, position ) { - if ( position === undefined ) { - position = objectb; - objectb = undefined; - } + class PointConstraint { + constructor ( objecta, objectb, position ) { + if ( position === undefined ) { + position = objectb; + objectb = undefined; + } - this.type = 'point'; - this.appliedImpulse = 0; - this.id = getObjectId(); - this.objecta = objecta._physijs.id; - this.positiona = convertWorldPositionToObject( position, objecta ).clone(); + this.type = 'point'; + this.appliedImpulse = 0; + this.id = getObjectId(); + this.objecta = objecta._physijs.id; + this.positiona = convertWorldPositionToObject( position, objecta ).clone(); - if ( objectb ) { - this.objectb = objectb._physijs.id; - this.positionb = convertWorldPositionToObject( position, objectb ).clone(); + if ( objectb ) { + this.objectb = objectb._physijs.id; + this.positionb = convertWorldPositionToObject( position, objectb ).clone(); + } } - }; - Physijs.PointConstraint.prototype.getDefinition = function() { - return { - type: this.type, - id: this.id, - objecta: this.objecta, - objectb: this.objectb, - positiona: this.positiona, - positionb: this.positionb - }; - }; - Physijs.HingeConstraint = function( objecta, objectb, position, axis ) { - if ( axis === undefined ) { - axis = position; - position = objectb; - objectb = undefined; + getDefinition() { + return { + type: this.type, + id: this.id, + objecta: this.objecta, + objectb: this.objectb, + positiona: this.positiona, + positionb: this.positionb + }; } + } - this.type = 'hinge'; - this.appliedImpulse = 0; - this.id = getObjectId(); - this.scene = objecta.parent; - this.objecta = objecta._physijs.id; - this.positiona = convertWorldPositionToObject( position, objecta ).clone(); - this.position = position.clone(); - this.axis = axis; + Physijs.PointConstraint = PointConstraint; - if ( objectb ) { - this.objectb = objectb._physijs.id; - this.positionb = convertWorldPositionToObject( position, objectb ).clone(); + class HingeConstraint { + constructor( objecta, objectb, position, axis ) { + if ( axis === undefined ) { + axis = position; + position = objectb; + objectb = undefined; + } + + this.type = 'hinge'; + this.appliedImpulse = 0; + this.id = getObjectId(); + this.scene = objecta.parent; + this.objecta = objecta._physijs.id; + this.positiona = convertWorldPositionToObject( position, objecta ).clone(); + this.position = position.clone(); + this.axis = axis; + + if ( objectb ) { + this.objectb = objectb._physijs.id; + this.positionb = convertWorldPositionToObject( position, objectb ).clone(); + } } - }; - Physijs.HingeConstraint.prototype.getDefinition = function() { - return { - type: this.type, - id: this.id, - objecta: this.objecta, - objectb: this.objectb, - positiona: this.positiona, - positionb: this.positionb, - axis: this.axis - }; - }; - /* - * low = minimum angle in radians - * high = maximum angle in radians - * bias_factor = applied as a factor to constraint error - * relaxation_factor = controls bounce (0.0 == no bounce) - */ - Physijs.HingeConstraint.prototype.setLimits = function( low, high, bias_factor, relaxation_factor ) { - this.scene.execute( 'hinge_setLimits', { constraint: this.id, low: low, high: high, bias_factor: bias_factor, relaxation_factor: relaxation_factor } ); - }; - Physijs.HingeConstraint.prototype.enableAngularMotor = function( velocity, acceleration ) { - this.scene.execute( 'hinge_enableAngularMotor', { constraint: this.id, velocity: velocity, acceleration: acceleration } ); - }; - Physijs.HingeConstraint.prototype.disableMotor = function( velocity, acceleration ) { - this.scene.execute( 'hinge_disableMotor', { constraint: this.id } ); - }; - Physijs.SliderConstraint = function( objecta, objectb, position, axis ) { - if ( axis === undefined ) { - axis = position; - position = objectb; - objectb = undefined; + getDefinition() { + return { + type: this.type, + id: this.id, + objecta: this.objecta, + objectb: this.objectb, + positiona: this.positiona, + positionb: this.positionb, + axis: this.axis + }; } - this.type = 'slider'; - this.appliedImpulse = 0; - this.id = getObjectId(); - this.scene = objecta.parent; - this.objecta = objecta._physijs.id; - this.positiona = convertWorldPositionToObject( position, objecta ).clone(); - this.axis = axis; + /* + * low = minimum angle in radians + * high = maximum angle in radians + * bias_factor = applied as a factor to constraint error + * relaxation_factor = controls bounce (0.0 == no bounce) + */ + setLimits( low, high, bias_factor, relaxation_factor ) { + this.scene.execute( 'hinge_setLimits', { constraint: this.id, low: low, high: high, bias_factor: bias_factor, relaxation_factor: relaxation_factor } ); + } - if ( objectb ) { - this.objectb = objectb._physijs.id; - this.positionb = convertWorldPositionToObject( position, objectb ).clone(); + enableAngularMotor( velocity, acceleration ) { + this.scene.execute( 'hinge_enableAngularMotor', { constraint: this.id, velocity: velocity, acceleration: acceleration } ); } - }; - Physijs.SliderConstraint.prototype.getDefinition = function() { - return { - type: this.type, - id: this.id, - objecta: this.objecta, - objectb: this.objectb, - positiona: this.positiona, - positionb: this.positionb, - axis: this.axis - }; - }; - Physijs.SliderConstraint.prototype.setLimits = function( lin_lower, lin_upper, ang_lower, ang_upper ) { - this.scene.execute( 'slider_setLimits', { constraint: this.id, lin_lower: lin_lower, lin_upper: lin_upper, ang_lower: ang_lower, ang_upper: ang_upper } ); - }; - Physijs.SliderConstraint.prototype.setRestitution = function( linear, angular ) { - this.scene.execute( - 'slider_setRestitution', - { - constraint: this.id, - linear: linear, - angular: angular + + disableMotor( velocity, acceleration ) { + this.scene.execute( 'hinge_disableMotor', { constraint: this.id } ); + } + } + + Physijs.HingeConstraint = HingeConstraint; + + class SliderConstraint { + constructor( objecta, objectb, position, axis ) { + if ( axis === undefined ) { + axis = position; + position = objectb; + objectb = undefined; } - ); - }; - Physijs.SliderConstraint.prototype.enableLinearMotor = function( velocity, acceleration) { - this.scene.execute( 'slider_enableLinearMotor', { constraint: this.id, velocity: velocity, acceleration: acceleration } ); - }; - Physijs.SliderConstraint.prototype.disableLinearMotor = function() { - this.scene.execute( 'slider_disableLinearMotor', { constraint: this.id } ); - }; - Physijs.SliderConstraint.prototype.enableAngularMotor = function( velocity, acceleration ) { - this.scene.execute( 'slider_enableAngularMotor', { constraint: this.id, velocity: velocity, acceleration: acceleration } ); - }; - Physijs.SliderConstraint.prototype.disableAngularMotor = function() { - this.scene.execute( 'slider_disableAngularMotor', { constraint: this.id } ); - }; - Physijs.ConeTwistConstraint = function( objecta, objectb, position ) { - if ( position === undefined ) { - throw 'Both objects must be defined in a ConeTwistConstraint.'; - } - this.type = 'conetwist'; - this.appliedImpulse = 0; - this.id = getObjectId(); - this.scene = objecta.parent; - this.objecta = objecta._physijs.id; - this.positiona = convertWorldPositionToObject( position, objecta ).clone(); - this.objectb = objectb._physijs.id; - this.positionb = convertWorldPositionToObject( position, objectb ).clone(); - this.axisa = { x: objecta.rotation.x, y: objecta.rotation.y, z: objecta.rotation.z }; - this.axisb = { x: objectb.rotation.x, y: objectb.rotation.y, z: objectb.rotation.z }; - }; - Physijs.ConeTwistConstraint.prototype.getDefinition = function() { - return { - type: this.type, - id: this.id, - objecta: this.objecta, - objectb: this.objectb, - positiona: this.positiona, - positionb: this.positionb, - axisa: this.axisa, - axisb: this.axisb - }; - }; - Physijs.ConeTwistConstraint.prototype.setLimit = function( x, y, z ) { - this.scene.execute( 'conetwist_setLimit', { constraint: this.id, x: x, y: y, z: z } ); - }; - Physijs.ConeTwistConstraint.prototype.enableMotor = function() { - this.scene.execute( 'conetwist_enableMotor', { constraint: this.id } ); - }; - Physijs.ConeTwistConstraint.prototype.setMaxMotorImpulse = function( max_impulse ) { - this.scene.execute( 'conetwist_setMaxMotorImpulse', { constraint: this.id, max_impulse: max_impulse } ); - }; - Physijs.ConeTwistConstraint.prototype.setMotorTarget = function( target ) { - if ( target instanceof THREE.Vector3 ) { - target = new THREE.Quaternion().setFromEuler( new THREE.Euler( target.x, target.y, target.z ) ); - } else if ( target instanceof THREE.Euler ) { - target = new THREE.Quaternion().setFromEuler( target ); - } else if ( target instanceof THREE.Matrix4 ) { - target = new THREE.Quaternion().setFromRotationMatrix( target ); - } - this.scene.execute( 'conetwist_setMotorTarget', { constraint: this.id, x: target.x, y: target.y, z: target.z, w: target.w } ); - }; - Physijs.ConeTwistConstraint.prototype.disableMotor = function() { - this.scene.execute( 'conetwist_disableMotor', { constraint: this.id } ); - }; + this.type = 'slider'; + this.appliedImpulse = 0; + this.id = getObjectId(); + this.scene = objecta.parent; + this.objecta = objecta._physijs.id; + this.positiona = convertWorldPositionToObject( position, objecta ).clone(); + this.axis = axis; + + if ( objectb ) { + this.objectb = objectb._physijs.id; + this.positionb = convertWorldPositionToObject( position, objectb ).clone(); + } + } + + getDefinition() { + return { + type: this.type, + id: this.id, + objecta: this.objecta, + objectb: this.objectb, + positiona: this.positiona, + positionb: this.positionb, + axis: this.axis + }; + } + + setLimits( lin_lower, lin_upper, ang_lower, ang_upper ) { + this.scene.execute( 'slider_setLimits', { constraint: this.id, lin_lower: lin_lower, lin_upper: lin_upper, ang_lower: ang_lower, ang_upper: ang_upper } ); + } + + setRestitution( linear, angular ) { + this.scene.execute( + 'slider_setRestitution', + { + constraint: this.id, + linear: linear, + angular: angular + } + ); + } + + enableLinearMotor( velocity, acceleration) { + this.scene.execute( 'slider_enableLinearMotor', { constraint: this.id, velocity: velocity, acceleration: acceleration } ); + } + + disableLinearMotor() { + this.scene.execute( 'slider_disableLinearMotor', { constraint: this.id } ); + } + + enableAngularMotor( velocity, acceleration ) { + this.scene.execute( 'slider_enableAngularMotor', { constraint: this.id, velocity: velocity, acceleration: acceleration } ); + } - Physijs.DOFConstraint = function( objecta, objectb, position ) { - if ( position === undefined ) { - position = objectb; - objectb = undefined; + disableAngularMotor() { + this.scene.execute( 'slider_disableAngularMotor', { constraint: this.id } ); } - this.type = 'dof'; - this.appliedImpulse = 0; - this.id = getObjectId(); - this.scene = objecta.parent; - this.objecta = objecta._physijs.id; - this.positiona = convertWorldPositionToObject( position, objecta ).clone(); - this.axisa = { x: objecta.rotation.x, y: objecta.rotation.y, z: objecta.rotation.z }; + } + + Physijs.SliderConstraint = SliderConstraint; - if ( objectb ) { + class ConeTwistConstraint { + constructor( objecta, objectb, position ) { + if ( position === undefined ) { + throw 'Both objects must be defined in a ConeTwistConstraint.'; + } + this.type = 'conetwist'; + this.appliedImpulse = 0; + this.id = getObjectId(); + this.scene = objecta.parent; + this.objecta = objecta._physijs.id; + this.positiona = convertWorldPositionToObject( position, objecta ).clone(); this.objectb = objectb._physijs.id; this.positionb = convertWorldPositionToObject( position, objectb ).clone(); + this.axisa = { x: objecta.rotation.x, y: objecta.rotation.y, z: objecta.rotation.z }; this.axisb = { x: objectb.rotation.x, y: objectb.rotation.y, z: objectb.rotation.z }; } - }; - Physijs.DOFConstraint.prototype.getDefinition = function() { - return { - type: this.type, - id: this.id, - objecta: this.objecta, - objectb: this.objectb, - positiona: this.positiona, - positionb: this.positionb, - axisa: this.axisa, - axisb: this.axisb - }; - }; - Physijs.DOFConstraint.prototype.setLinearLowerLimit = function( limit ) { - this.scene.execute( 'dof_setLinearLowerLimit', { constraint: this.id, x: limit.x, y: limit.y, z: limit.z } ); - }; - Physijs.DOFConstraint.prototype.setLinearUpperLimit = function( limit ) { - this.scene.execute( 'dof_setLinearUpperLimit', { constraint: this.id, x: limit.x, y: limit.y, z: limit.z } ); - }; - Physijs.DOFConstraint.prototype.setAngularLowerLimit = function( limit ) { - this.scene.execute( 'dof_setAngularLowerLimit', { constraint: this.id, x: limit.x, y: limit.y, z: limit.z } ); - }; - Physijs.DOFConstraint.prototype.setAngularUpperLimit = function( limit ) { - this.scene.execute( 'dof_setAngularUpperLimit', { constraint: this.id, x: limit.x, y: limit.y, z: limit.z } ); - }; - Physijs.DOFConstraint.prototype.enableAngularMotor = function( which ) { - this.scene.execute( 'dof_enableAngularMotor', { constraint: this.id, which: which } ); - }; - Physijs.DOFConstraint.prototype.configureAngularMotor = function( which, low_angle, high_angle, velocity, max_force ) { - this.scene.execute( 'dof_configureAngularMotor', { constraint: this.id, which: which, low_angle: low_angle, high_angle: high_angle, velocity: velocity, max_force: max_force } ); - }; - Physijs.DOFConstraint.prototype.disableAngularMotor = function( which ) { - this.scene.execute( 'dof_disableAngularMotor', { constraint: this.id, which: which } ); - }; - // Physijs.Scene - Physijs.Scene = function( params ) { - var self = this; + getDefinition() { + return { + type: this.type, + id: this.id, + objecta: this.objecta, + objectb: this.objectb, + positiona: this.positiona, + positionb: this.positionb, + axisa: this.axisa, + axisb: this.axisb + }; + } - Eventable.call( this ); - THREE.Scene.call( this ); + setLimit( x, y, z ) { + this.scene.execute( 'conetwist_setLimit', { constraint: this.id, x: x, y: y, z: z } ); + } + + enableMotor() { + this.scene.execute( 'conetwist_enableMotor', { constraint: this.id } ); + } - this._worker = new Worker( Physijs.scripts.worker || 'physijs_worker.js' ); - this._worker.transferableMessage = this._worker.webkitPostMessage || this._worker.postMessage; - this._materials_ref_counts = {}; - this._objects = {}; - this._vehicles = {}; - this._constraints = {}; + setMaxMotorImpulse( max_impulse ) { + this.scene.execute( 'conetwist_setMaxMotorImpulse', { constraint: this.id, max_impulse: max_impulse } ); + } + + setMotorTarget( target ) { + if ( target instanceof THREE.Vector3 ) { + target = new THREE.Quaternion().setFromEuler( new THREE.Euler( target.x, target.y, target.z ) ); + } else if ( target instanceof THREE.Euler ) { + target = new THREE.Quaternion().setFromEuler( target ); + } else if ( target instanceof THREE.Matrix4 ) { + target = new THREE.Quaternion().setFromRotationMatrix( target ); + } + this.scene.execute( 'conetwist_setMotorTarget', { constraint: this.id, x: target.x, y: target.y, z: target.z, w: target.w } ); + } - var ab = new ArrayBuffer( 1 ); - this._worker.transferableMessage( ab, [ab] ); - SUPPORT_TRANSFERABLE = ( ab.byteLength === 0 ); + disableMotor() { + this.scene.execute( 'conetwist_disableMotor', { constraint: this.id } ); + } + } - this._worker.onmessage = function ( event ) { - var _temp, - data = event.data; + Physijs.ConeTwistConstraint = ConeTwistConstraint; - if ( data instanceof ArrayBuffer && data.byteLength !== 1 ) { // byteLength === 1 is the worker making a SUPPORT_TRANSFERABLE test - data = new Float32Array( data ); + class DOFConstraint { + constructor( objecta, objectb, position ) { + if ( position === undefined ) { + position = objectb; + objectb = undefined; } + this.type = 'dof'; + this.appliedImpulse = 0; + this.id = getObjectId(); + this.scene = objecta.parent; + this.objecta = objecta._physijs.id; + this.positiona = convertWorldPositionToObject( position, objecta ).clone(); + this.axisa = { x: objecta.rotation.x, y: objecta.rotation.y, z: objecta.rotation.z }; + + if ( objectb ) { + this.objectb = objectb._physijs.id; + this.positionb = convertWorldPositionToObject( position, objectb ).clone(); + this.axisb = { x: objectb.rotation.x, y: objectb.rotation.y, z: objectb.rotation.z }; + } + } + + getDefinition() { + return { + type: this.type, + id: this.id, + objecta: this.objecta, + objectb: this.objectb, + positiona: this.positiona, + positionb: this.positionb, + axisa: this.axisa, + axisb: this.axisb + }; + } - if ( data instanceof Float32Array ) { - - // transferable object - switch ( data[0] ) { - case MESSAGE_TYPES.WORLDREPORT: - self._updateScene( data ); - break; - - case MESSAGE_TYPES.COLLISIONREPORT: - self._updateCollisions( data ); - break; + setLinearLowerLimit( limit ) { + this.scene.execute( 'dof_setLinearLowerLimit', { constraint: this.id, x: limit.x, y: limit.y, z: limit.z } ); + } - case MESSAGE_TYPES.VEHICLEREPORT: - self._updateVehicles( data ); - break; + setLinearUpperLimit( limit ) { + this.scene.execute( 'dof_setLinearUpperLimit', { constraint: this.id, x: limit.x, y: limit.y, z: limit.z } ); + } - case MESSAGE_TYPES.CONSTRAINTREPORT: - self._updateConstraints( data ); - break; - } + setAngularLowerLimit( limit ) { + this.scene.execute( 'dof_setAngularLowerLimit', { constraint: this.id, x: limit.x, y: limit.y, z: limit.z } ); + } - } else { + setAngularUpperLimit( limit ) { + this.scene.execute( 'dof_setAngularUpperLimit', { constraint: this.id, x: limit.x, y: limit.y, z: limit.z } ); + } - if ( data.cmd ) { + enableAngularMotor( which ) { + this.scene.execute( 'dof_enableAngularMotor', { constraint: this.id, which: which } ); + } - // non-transferable object - switch ( data.cmd ) { - case 'objectReady': - _temp = data.params; - if ( self._objects[ _temp ] ) { - self._objects[ _temp ].dispatchEvent( 'ready' ); - } - break; + configureAngularMotor( which, low_angle, high_angle, velocity, max_force ) { + this.scene.execute( 'dof_configureAngularMotor', { constraint: this.id, which: which, low_angle: low_angle, high_angle: high_angle, velocity: velocity, max_force: max_force } ); + } - case 'worldReady': - self.dispatchEvent( 'ready' ); - break; + disableAngularMotor( which ) { + this.scene.execute( 'dof_disableAngularMotor', { constraint: this.id, which: which } ); + } + } - case 'vehicle': - window.test = data; - break; + Physijs.DOFConstraint = DOFConstraint; - default: - // Do nothing, just show the message - console.debug('Received: ' + data.cmd); - console.dir(data.params); - break; - } + // Physijs.Scene + class Scene extends Eventable(THREE.Scene) { + constructor( params ) { + super(params); + var self = this; + + this._worker = new Worker( Physijs.scripts.worker || 'physijs_worker.js' ); + this._worker.transferableMessage = this._worker.webkitPostMessage || this._worker.postMessage; + this._materials_ref_counts = {}; + this._objects = {}; + this._vehicles = {}; + this._constraints = {}; + + var ab = new ArrayBuffer( 1 ); + this._worker.transferableMessage( ab, [ab] ); + SUPPORT_TRANSFERABLE = ( ab.byteLength === 0 ); + + this._worker.onmessage = function ( event ) { + var _temp, + data = event.data; + + if ( data instanceof ArrayBuffer && data.byteLength !== 1 ) { // byteLength === 1 is the worker making a SUPPORT_TRANSFERABLE test + data = new Float32Array( data ); + } - } else { + if ( data instanceof Float32Array ) { + // transferable object switch ( data[0] ) { case MESSAGE_TYPES.WORLDREPORT: self._updateScene( data ); @@ -478,317 +476,493 @@ window.Physijs = (function() { break; } + } else { + + if ( data.cmd ) { + + // non-transferable object + switch ( data.cmd ) { + case 'objectReady': + _temp = data.params; + if ( self._objects[ _temp ] ) { + self._objects[ _temp ].dispatchEvent( 'ready' ); + } + break; + + case 'worldReady': + self.dispatchEvent( 'ready' ); + break; + + case 'vehicle': + window.test = data; + break; + + default: + // Do nothing, just show the message + console.debug('Received: ' + data.cmd); + console.dir(data.params); + break; + } + + } else { + + switch ( data[0] ) { + case MESSAGE_TYPES.WORLDREPORT: + self._updateScene( data ); + break; + + case MESSAGE_TYPES.COLLISIONREPORT: + self._updateCollisions( data ); + break; + + case MESSAGE_TYPES.VEHICLEREPORT: + self._updateVehicles( data ); + break; + + case MESSAGE_TYPES.CONSTRAINTREPORT: + self._updateConstraints( data ); + break; + } + + } + } + }; - } - }; + params = params || {}; + params.ammo = Physijs.scripts.ammo || 'ammo.js'; + params.fixedTimeStep = params.fixedTimeStep || 1 / 60; + params.rateLimit = params.rateLimit || true; + this.execute( 'init', params ); + } + + _updateScene( data ) { + var num_objects = data[1], + object, + i, offset; - params = params || {}; - params.ammo = Physijs.scripts.ammo || 'ammo.js'; - params.fixedTimeStep = params.fixedTimeStep || 1 / 60; - params.rateLimit = params.rateLimit || true; - this.execute( 'init', params ); - }; - Physijs.Scene.prototype = new THREE.Scene; - Physijs.Scene.prototype.constructor = Physijs.Scene; - Eventable.make( Physijs.Scene ); + for ( i = 0; i < num_objects; i++ ) { + offset = 2 + i * REPORT_ITEMSIZE; + object = this._objects[ data[ offset ] ]; + + if ( object === undefined ) { + continue; + } - Physijs.Scene.prototype._updateScene = function( data ) { - var num_objects = data[1], - object, - i, offset; + if ( object.__dirtyPosition === false ) { + object.position.set( + data[ offset + 1 ], + data[ offset + 2 ], + data[ offset + 3 ] + ); + } - for ( i = 0; i < num_objects; i++ ) { - offset = 2 + i * REPORT_ITEMSIZE; - object = this._objects[ data[ offset ] ]; + if ( object.__dirtyRotation === false ) { + object.quaternion.set( + data[ offset + 4 ], + data[ offset + 5 ], + data[ offset + 6 ], + data[ offset + 7 ] + ); + } + + object._physijs.linearVelocity.set( + data[ offset + 8 ], + data[ offset + 9 ], + data[ offset + 10 ] + ); + + object._physijs.angularVelocity.set( + data[ offset + 11 ], + data[ offset + 12 ], + data[ offset + 13 ] + ); - if ( object === undefined ) { - continue; } - if ( object.__dirtyPosition === false ) { - object.position.set( - data[ offset + 1 ], + if ( SUPPORT_TRANSFERABLE ) { + // Give the typed array back to the worker + this._worker.transferableMessage( data.buffer, [data.buffer] ); + } + + _is_simulating = false; + this.dispatchEvent( 'update' ); + } + + _updateVehicles( data ) { + var vehicle, wheel, + i, offset; + + for ( i = 0; i < ( data.length - 1 ) / VEHICLEREPORT_ITEMSIZE; i++ ) { + offset = 1 + i * VEHICLEREPORT_ITEMSIZE; + vehicle = this._vehicles[ data[ offset ] ]; + + if ( vehicle === undefined ) { + continue; + } + + wheel = vehicle.wheels[ data[ offset + 1 ] ]; + + wheel.position.set( data[ offset + 2 ], - data[ offset + 3 ] + data[ offset + 3 ], + data[ offset + 4 ] ); - } - if ( object.__dirtyRotation === false ) { - object.quaternion.set( - data[ offset + 4 ], + wheel.quaternion.set( data[ offset + 5 ], data[ offset + 6 ], - data[ offset + 7 ] + data[ offset + 7 ], + data[ offset + 8 ] ); } - object._physijs.linearVelocity.set( - data[ offset + 8 ], - data[ offset + 9 ], - data[ offset + 10 ] - ); + if ( SUPPORT_TRANSFERABLE ) { + // Give the typed array back to the worker + this._worker.transferableMessage( data.buffer, [data.buffer] ); + } + } - object._physijs.angularVelocity.set( - data[ offset + 11 ], - data[ offset + 12 ], - data[ offset + 13 ] - ); + _updateConstraints( data ) { + var constraint, object, + i, offset; - } + for ( i = 0; i < ( data.length - 1 ) / CONSTRAINTREPORT_ITEMSIZE; i++ ) { + offset = 1 + i * CONSTRAINTREPORT_ITEMSIZE; + constraint = this._constraints[ data[ offset ] ]; + object = this._objects[ data[ offset + 1 ] ]; - if ( SUPPORT_TRANSFERABLE ) { - // Give the typed array back to the worker - this._worker.transferableMessage( data.buffer, [data.buffer] ); - } + if ( constraint === undefined || object === undefined ) { + continue; + } - _is_simulating = false; - this.dispatchEvent( 'update' ); - }; + _temp_vector3_1.set( + data[ offset + 2 ], + data[ offset + 3 ], + data[ offset + 4 ] + ); + _temp_matrix4_1.extractRotation( object.matrix ); + _temp_vector3_1.applyMatrix4( _temp_matrix4_1 ); - Physijs.Scene.prototype._updateVehicles = function( data ) { - var vehicle, wheel, - i, offset; + constraint.positiona.addVectors( object.position, _temp_vector3_1 ); + constraint.appliedImpulse = data[ offset + 5 ] ; + } - for ( i = 0; i < ( data.length - 1 ) / VEHICLEREPORT_ITEMSIZE; i++ ) { - offset = 1 + i * VEHICLEREPORT_ITEMSIZE; - vehicle = this._vehicles[ data[ offset ] ]; + if ( SUPPORT_TRANSFERABLE ) { + // Give the typed array back to the worker + this._worker.transferableMessage( data.buffer, [data.buffer] ); + } + } - if ( vehicle === undefined ) { - continue; + _updateCollisions( data ) { + /** + * #TODO + * This is probably the worst way ever to handle collisions. The inherent evilness is a residual + * effect from the previous version's evilness which mutated when switching to transferable objects. + * + * If you feel inclined to make this better, please do so. + */ + + var i, j, offset, object, object2, id1, id2, + collisions = {}, normal_offsets = {}; + + // Build collision manifest + for ( i = 0; i < data[1]; i++ ) { + offset = 2 + i * COLLISIONREPORT_ITEMSIZE; + object = data[ offset ]; + object2 = data[ offset + 1 ]; + + normal_offsets[ object + '-' + object2 ] = offset + 2; + normal_offsets[ object2 + '-' + object ] = -1 * ( offset + 2 ); + + // Register collisions for both the object colliding and the object being collided with + if ( !collisions[ object ] ) collisions[ object ] = []; + collisions[ object ].push( object2 ); + + if ( !collisions[ object2 ] ) collisions[ object2 ] = []; + collisions[ object2 ].push( object ); } - wheel = vehicle.wheels[ data[ offset + 1 ] ]; + // Deal with collisions + for ( id1 in this._objects ) { + if ( !this._objects.hasOwnProperty( id1 ) ) continue; + object = this._objects[ id1 ]; - wheel.position.set( - data[ offset + 2 ], - data[ offset + 3 ], - data[ offset + 4 ] - ); + // If object touches anything, ... + if ( collisions[ id1 ] ) { - wheel.quaternion.set( - data[ offset + 5 ], - data[ offset + 6 ], - data[ offset + 7 ], - data[ offset + 8 ] - ); - } + // Clean up touches array + for ( j = 0; j < object._physijs.touches.length; j++ ) { + if ( collisions[ id1 ].indexOf( object._physijs.touches[j] ) === -1 ) { + object._physijs.touches.splice( j--, 1 ); + } + } + + // Handle each colliding object + for ( j = 0; j < collisions[ id1 ].length; j++ ) { + id2 = collisions[ id1 ][ j ]; + object2 = this._objects[ id2 ]; + + if ( object2 ) { + // If object was not already touching object2, notify object + if ( object._physijs.touches.indexOf( id2 ) === -1 ) { + object._physijs.touches.push( id2 ); + + _temp_vector3_1.subVectors( object.getLinearVelocity(), object2.getLinearVelocity() ); + _temp1 = _temp_vector3_1.clone(); + + _temp_vector3_1.subVectors( object.getAngularVelocity(), object2.getAngularVelocity() ); + _temp2 = _temp_vector3_1.clone(); + + var normal_offset = normal_offsets[ object._physijs.id + '-' + object2._physijs.id ]; + if ( normal_offset > 0 ) { + _temp_vector3_1.set( + -data[ normal_offset ], + -data[ normal_offset + 1 ], + -data[ normal_offset + 2 ] + ); + } else { + normal_offset *= -1; + _temp_vector3_1.set( + data[ normal_offset ], + data[ normal_offset + 1 ], + data[ normal_offset + 2 ] + ); + } + + object.dispatchEvent( 'collision', object2, _temp1, _temp2, _temp_vector3_1 ); + } + } + } + + } else { + + // not touching other objects + object._physijs.touches.length = 0; - if ( SUPPORT_TRANSFERABLE ) { - // Give the typed array back to the worker - this._worker.transferableMessage( data.buffer, [data.buffer] ); + } + + } + + this.collisions = collisions; + + if ( SUPPORT_TRANSFERABLE ) { + // Give the typed array back to the worker + this._worker.transferableMessage( data.buffer, [data.buffer] ); + } } - }; - Physijs.Scene.prototype._updateConstraints = function( data ) { - var constraint, object, - i, offset; + addConstraint( constraint, show_marker ) { + this._constraints[ constraint.id ] = constraint; + this.execute( 'addConstraint', constraint.getDefinition() ); + + if ( show_marker ) { + var marker; + + switch ( constraint.type ) { + case 'point': + marker = new THREE.Mesh( + new THREE.SphereGeometry( 1.5 ), + new THREE.MeshNormalMaterial + ); + marker.position.copy( constraint.positiona ); + this._objects[ constraint.objecta ].add( marker ); + break; + + case 'hinge': + marker = new THREE.Mesh( + new THREE.SphereGeometry( 1.5 ), + new THREE.MeshNormalMaterial + ); + marker.position.copy( constraint.positiona ); + this._objects[ constraint.objecta ].add( marker ); + break; - for ( i = 0; i < ( data.length - 1 ) / CONSTRAINTREPORT_ITEMSIZE; i++ ) { - offset = 1 + i * CONSTRAINTREPORT_ITEMSIZE; - constraint = this._constraints[ data[ offset ] ]; - object = this._objects[ data[ offset + 1 ] ]; + case 'slider': + marker = new THREE.Mesh( + new THREE.BoxGeometry( 10, 1, 1 ), + new THREE.MeshNormalMaterial + ); + marker.position.copy( constraint.positiona ); + // This rotation isn't right if all three axis are non-0 values + // TODO: change marker's rotation order to ZYX + marker.rotation.set( + constraint.axis.y, // yes, y and + constraint.axis.x, // x axis are swapped + constraint.axis.z + ); + this._objects[ constraint.objecta ].add( marker ); + break; - if ( constraint === undefined || object === undefined ) { - continue; + case 'conetwist': + marker = new THREE.Mesh( + new THREE.SphereGeometry( 1.5 ), + new THREE.MeshNormalMaterial + ); + marker.position.copy( constraint.positiona ); + this._objects[ constraint.objecta ].add( marker ); + break; + + case 'dof': + marker = new THREE.Mesh( + new THREE.SphereGeometry( 1.5 ), + new THREE.MeshNormalMaterial + ); + marker.position.copy( constraint.positiona ); + this._objects[ constraint.objecta ].add( marker ); + break; + } } - _temp_vector3_1.set( - data[ offset + 2 ], - data[ offset + 3 ], - data[ offset + 4 ] - ); - _temp_matrix4_1.extractRotation( object.matrix ); - _temp_vector3_1.applyMatrix4( _temp_matrix4_1 ); + return constraint; + } - constraint.positiona.addVectors( object.position, _temp_vector3_1 ); - constraint.appliedImpulse = data[ offset + 5 ] ; + onSimulationResume() { + this.execute( 'onSimulationResume', { } ); } - if ( SUPPORT_TRANSFERABLE ) { - // Give the typed array back to the worker - this._worker.transferableMessage( data.buffer, [data.buffer] ); + removeConstraint( constraint ) { + if ( this._constraints[constraint.id ] !== undefined ) { + this.execute( 'removeConstraint', { id: constraint.id } ); + delete this._constraints[ constraint.id ]; + } } - }; - Physijs.Scene.prototype._updateCollisions = function( data ) { - /** - * #TODO - * This is probably the worst way ever to handle collisions. The inherent evilness is a residual - * effect from the previous version's evilness which mutated when switching to transferable objects. - * - * If you feel inclined to make this better, please do so. - */ + execute( cmd, params ) { + this._worker.postMessage({ cmd: cmd, params: params }); + }; - var i, j, offset, object, object2, id1, id2, - collisions = {}, normal_offsets = {}; + add( object ) { + super.add( object ); - // Build collision manifest - for ( i = 0; i < data[1]; i++ ) { - offset = 2 + i * COLLISIONREPORT_ITEMSIZE; - object = data[ offset ]; - object2 = data[ offset + 1 ]; + if ( object._physijs ) { - normal_offsets[ object + '-' + object2 ] = offset + 2; - normal_offsets[ object2 + '-' + object ] = -1 * ( offset + 2 ); + object.world = this; - // Register collisions for both the object colliding and the object being collided with - if ( !collisions[ object ] ) collisions[ object ] = []; - collisions[ object ].push( object2 ); + if ( object instanceof Physijs.Vehicle ) { - if ( !collisions[ object2 ] ) collisions[ object2 ] = []; - collisions[ object2 ].push( object ); - } + this.add( object.mesh ); + this._vehicles[ object._physijs.id ] = object; + this.execute( 'addVehicle', object._physijs ); - // Deal with collisions - for ( id1 in this._objects ) { - if ( !this._objects.hasOwnProperty( id1 ) ) continue; - object = this._objects[ id1 ]; + } else { - // If object touches anything, ... - if ( collisions[ id1 ] ) { + object.__dirtyPosition = false; + object.__dirtyRotation = false; + this._objects[object._physijs.id] = object; - // Clean up touches array - for ( j = 0; j < object._physijs.touches.length; j++ ) { - if ( collisions[ id1 ].indexOf( object._physijs.touches[j] ) === -1 ) { - object._physijs.touches.splice( j--, 1 ); + if ( object.children.length ) { + object._physijs.children = []; + addObjectChildren( object, object ); } - } - - // Handle each colliding object - for ( j = 0; j < collisions[ id1 ].length; j++ ) { - id2 = collisions[ id1 ][ j ]; - object2 = this._objects[ id2 ]; - - if ( object2 ) { - // If object was not already touching object2, notify object - if ( object._physijs.touches.indexOf( id2 ) === -1 ) { - object._physijs.touches.push( id2 ); - - _temp_vector3_1.subVectors( object.getLinearVelocity(), object2.getLinearVelocity() ); - _temp1 = _temp_vector3_1.clone(); - - _temp_vector3_1.subVectors( object.getAngularVelocity(), object2.getAngularVelocity() ); - _temp2 = _temp_vector3_1.clone(); - - var normal_offset = normal_offsets[ object._physijs.id + '-' + object2._physijs.id ]; - if ( normal_offset > 0 ) { - _temp_vector3_1.set( - -data[ normal_offset ], - -data[ normal_offset + 1 ], - -data[ normal_offset + 2 ] - ); - } else { - normal_offset *= -1; - _temp_vector3_1.set( - data[ normal_offset ], - data[ normal_offset + 1 ], - data[ normal_offset + 2 ] - ); - } - object.dispatchEvent( 'collision', object2, _temp1, _temp2, _temp_vector3_1 ); + if ( object.material._physijs ) { + if ( !this._materials_ref_counts.hasOwnProperty( object.material._physijs.id ) ) { + this.execute( 'registerMaterial', object.material._physijs ); + object._physijs.materialId = object.material._physijs.id; + this._materials_ref_counts[object.material._physijs.id] = 1; + } else { + this._materials_ref_counts[object.material._physijs.id]++; } } - } - } else { + // Object starting position + rotation + object._physijs.position = { x: object.position.x, y: object.position.y, z: object.position.z }; + object._physijs.rotation = { x: object.quaternion.x, y: object.quaternion.y, z: object.quaternion.z, w: object.quaternion.w }; - // not touching other objects - object._physijs.touches.length = 0; + // Check for scaling + var mass_scaling = new THREE.Vector3( 1, 1, 1 ); + if ( object._physijs.width ) { + object._physijs.width *= object.scale.x; + } + if ( object._physijs.height ) { + object._physijs.height *= object.scale.y; + } + if ( object._physijs.depth ) { + object._physijs.depth *= object.scale.z; + } + + this.execute( 'addObject', object._physijs ); + } } + } + remove( object ) { + if ( object instanceof Physijs.Vehicle ) { + this.execute( 'removeVehicle', { id: object._physijs.id } ); + while( object.wheels.length ) { + this.remove( object.wheels.pop() ); + } + this.remove( object.mesh ); + delete this._vehicles[ object._physijs.id ]; + } else { + super.remove( object ); + if ( object._physijs ) { + delete this._objects[object._physijs.id]; + this.execute( 'removeObject', { id: object._physijs.id } ); + } + } + if ( object.material && object.material._physijs && this._materials_ref_counts.hasOwnProperty( object.material._physijs.id ) ) { + this._materials_ref_counts[object.material._physijs.id]--; + if(this._materials_ref_counts[object.material._physijs.id] == 0) { + this.execute( 'unRegisterMaterial', object.material._physijs ); + delete this._materials_ref_counts[object.material._physijs.id]; + } + } } - this.collisions = collisions; + setFixedTimeStep( fixedTimeStep ) { + if ( fixedTimeStep ) { + this.execute( 'setFixedTimeStep', fixedTimeStep ); + } + } - if ( SUPPORT_TRANSFERABLE ) { - // Give the typed array back to the worker - this._worker.transferableMessage( data.buffer, [data.buffer] ); + setGravity( gravity ) { + if ( gravity ) { + this.execute( 'setGravity', gravity ); + } } - }; - Physijs.Scene.prototype.addConstraint = function ( constraint, show_marker ) { - this._constraints[ constraint.id ] = constraint; - this.execute( 'addConstraint', constraint.getDefinition() ); + simulate( timeStep, maxSubSteps ) { + var object_id, object, update; - if ( show_marker ) { - var marker; + if ( _is_simulating ) { + return false; + } - switch ( constraint.type ) { - case 'point': - marker = new THREE.Mesh( - new THREE.SphereGeometry( 1.5 ), - new THREE.MeshNormalMaterial - ); - marker.position.copy( constraint.positiona ); - this._objects[ constraint.objecta ].add( marker ); - break; - - case 'hinge': - marker = new THREE.Mesh( - new THREE.SphereGeometry( 1.5 ), - new THREE.MeshNormalMaterial - ); - marker.position.copy( constraint.positiona ); - this._objects[ constraint.objecta ].add( marker ); - break; - - case 'slider': - marker = new THREE.Mesh( - new THREE.BoxGeometry( 10, 1, 1 ), - new THREE.MeshNormalMaterial - ); - marker.position.copy( constraint.positiona ); - // This rotation isn't right if all three axis are non-0 values - // TODO: change marker's rotation order to ZYX - marker.rotation.set( - constraint.axis.y, // yes, y and - constraint.axis.x, // x axis are swapped - constraint.axis.z - ); - this._objects[ constraint.objecta ].add( marker ); - break; + _is_simulating = true; - case 'conetwist': - marker = new THREE.Mesh( - new THREE.SphereGeometry( 1.5 ), - new THREE.MeshNormalMaterial - ); - marker.position.copy( constraint.positiona ); - this._objects[ constraint.objecta ].add( marker ); - break; - - case 'dof': - marker = new THREE.Mesh( - new THREE.SphereGeometry( 1.5 ), - new THREE.MeshNormalMaterial - ); - marker.position.copy( constraint.positiona ); - this._objects[ constraint.objecta ].add( marker ); - break; - } - } + for ( object_id in this._objects ) { + if ( !this._objects.hasOwnProperty( object_id ) ) continue; - return constraint; - }; + object = this._objects[object_id]; - Physijs.Scene.prototype.onSimulationResume = function() { - this.execute( 'onSimulationResume', { } ); - }; + if ( object.__dirtyPosition || object.__dirtyRotation ) { + update = { id: object._physijs.id }; - Physijs.Scene.prototype.removeConstraint = function( constraint ) { - if ( this._constraints[constraint.id ] !== undefined ) { - this.execute( 'removeConstraint', { id: constraint.id } ); - delete this._constraints[ constraint.id ]; - } - }; + if ( object.__dirtyPosition ) { + update.pos = { x: object.position.x, y: object.position.y, z: object.position.z }; + object.__dirtyPosition = false; + } - Physijs.Scene.prototype.execute = function( cmd, params ) { - this._worker.postMessage({ cmd: cmd, params: params }); - }; + if ( object.__dirtyRotation ) { + update.quat = { x: object.quaternion.x, y: object.quaternion.y, z: object.quaternion.z, w: object.quaternion.w }; + object.__dirtyRotation = false; + } + + this.execute( 'updateTransform', update ); + } + } + + this.execute( 'simulate', { timeStep: timeStep, maxSubSteps: maxSubSteps } ); + + return true; + } + } + + Physijs.Scene = Scene; addObjectChildren = function( parent, object ) { var i; @@ -821,573 +995,464 @@ window.Physijs = (function() { } }; - Physijs.Scene.prototype.add = function( object ) { - THREE.Mesh.prototype.add.call( this, object ); - - if ( object._physijs ) { - - object.world = this; - - if ( object instanceof Physijs.Vehicle ) { - - this.add( object.mesh ); - this._vehicles[ object._physijs.id ] = object; - this.execute( 'addVehicle', object._physijs ); - - } else { - - object.__dirtyPosition = false; - object.__dirtyRotation = false; - this._objects[object._physijs.id] = object; - - if ( object.children.length ) { - object._physijs.children = []; - addObjectChildren( object, object ); - } - - if ( object.material._physijs ) { - if ( !this._materials_ref_counts.hasOwnProperty( object.material._physijs.id ) ) { - this.execute( 'registerMaterial', object.material._physijs ); - object._physijs.materialId = object.material._physijs.id; - this._materials_ref_counts[object.material._physijs.id] = 1; - } else { - this._materials_ref_counts[object.material._physijs.id]++; - } - } - - // Object starting position + rotation - object._physijs.position = { x: object.position.x, y: object.position.y, z: object.position.z }; - object._physijs.rotation = { x: object.quaternion.x, y: object.quaternion.y, z: object.quaternion.z, w: object.quaternion.w }; + // Phsijs.Mesh + class Mesh extends Eventable(THREE.Mesh) { + constructor( geometry, material, mass ) { + var index; - // Check for scaling - var mass_scaling = new THREE.Vector3( 1, 1, 1 ); - if ( object._physijs.width ) { - object._physijs.width *= object.scale.x; - } - if ( object._physijs.height ) { - object._physijs.height *= object.scale.y; - } - if ( object._physijs.depth ) { - object._physijs.depth *= object.scale.z; - } + if ( !geometry ) { + return; + } - this.execute( 'addObject', object._physijs ); + super(geometry, material); + if ( !geometry.boundingBox ) { + geometry.computeBoundingBox(); } - } - }; - Physijs.Scene.prototype.remove = function( object ) { - if ( object instanceof Physijs.Vehicle ) { - this.execute( 'removeVehicle', { id: object._physijs.id } ); - while( object.wheels.length ) { - this.remove( object.wheels.pop() ); - } - this.remove( object.mesh ); - delete this._vehicles[ object._physijs.id ]; - } else { - THREE.Mesh.prototype.remove.call( this, object ); - if ( object._physijs ) { - delete this._objects[object._physijs.id]; - this.execute( 'removeObject', { id: object._physijs.id } ); - } - } - if ( object.material && object.material._physijs && this._materials_ref_counts.hasOwnProperty( object.material._physijs.id ) ) { - this._materials_ref_counts[object.material._physijs.id]--; - if(this._materials_ref_counts[object.material._physijs.id] == 0) { - this.execute( 'unRegisterMaterial', object.material._physijs ); - delete this._materials_ref_counts[object.material._physijs.id]; - } + this._physijs = { + type: null, + id: getObjectId(), + mass: mass || 0, + touches: [], + linearVelocity: new THREE.Vector3, + angularVelocity: new THREE.Vector3 + }; } - }; - Physijs.Scene.prototype.setFixedTimeStep = function( fixedTimeStep ) { - if ( fixedTimeStep ) { - this.execute( 'setFixedTimeStep', fixedTimeStep ); + // Physijs.Mesh.mass + get mass() { + return this._physijs.mass; } - }; - Physijs.Scene.prototype.setGravity = function( gravity ) { - if ( gravity ) { - this.execute( 'setGravity', gravity ); + set mass( mass ) { + this._physijs.mass = mass; + if ( this.world ) { + this.world.execute( 'updateMass', { id: this._physijs.id, mass: mass } ); + } } - }; - - Physijs.Scene.prototype.simulate = function( timeStep, maxSubSteps ) { - var object_id, object, update; - if ( _is_simulating ) { - return false; + // Physijs.Mesh.applyCentralImpulse + applyCentralImpulse( force ) { + if ( this.world ) { + this.world.execute( 'applyCentralImpulse', { id: this._physijs.id, x: force.x, y: force.y, z: force.z } ); + } } - _is_simulating = true; - - for ( object_id in this._objects ) { - if ( !this._objects.hasOwnProperty( object_id ) ) continue; - - object = this._objects[object_id]; - - if ( object.__dirtyPosition || object.__dirtyRotation ) { - update = { id: object._physijs.id }; - - if ( object.__dirtyPosition ) { - update.pos = { x: object.position.x, y: object.position.y, z: object.position.z }; - object.__dirtyPosition = false; - } - - if ( object.__dirtyRotation ) { - update.quat = { x: object.quaternion.x, y: object.quaternion.y, z: object.quaternion.z, w: object.quaternion.w }; - object.__dirtyRotation = false; - } - - this.execute( 'updateTransform', update ); + // Physijs.Mesh.applyImpulse + applyImpulse( force, offset ) { + if ( this.world ) { + this.world.execute( 'applyImpulse', { id: this._physijs.id, impulse_x: force.x, impulse_y: force.y, impulse_z: force.z, x: offset.x, y: offset.y, z: offset.z } ); } } - this.execute( 'simulate', { timeStep: timeStep, maxSubSteps: maxSubSteps } ); - - return true; - }; - - - // Phsijs.Mesh - Physijs.Mesh = function ( geometry, material, mass ) { - var index; - - if ( !geometry ) { - return; + // Physijs.Mesh.applyTorque + applyTorque( force ) { + if ( this.world ) { + this.world.execute( 'applyTorque', { id: this._physijs.id, torque_x: force.x, torque_y: force.y, torque_z: force.z } ); + } } - Eventable.call( this ); - THREE.Mesh.call( this, geometry, material ); - - if ( !geometry.boundingBox ) { - geometry.computeBoundingBox(); + // Physijs.Mesh.applyCentralForce + applyCentralForce( force ) { + if ( this.world ) { + this.world.execute( 'applyCentralForce', { id: this._physijs.id, x: force.x, y: force.y, z: force.z } ); + } } - this._physijs = { - type: null, - id: getObjectId(), - mass: mass || 0, - touches: [], - linearVelocity: new THREE.Vector3, - angularVelocity: new THREE.Vector3 - }; - }; - Physijs.Mesh.prototype = new THREE.Mesh; - Physijs.Mesh.prototype.constructor = Physijs.Mesh; - Eventable.make( Physijs.Mesh ); - - // Physijs.Mesh.mass - Physijs.Mesh.prototype.__defineGetter__('mass', function() { - return this._physijs.mass; - }); - Physijs.Mesh.prototype.__defineSetter__('mass', function( mass ) { - this._physijs.mass = mass; - if ( this.world ) { - this.world.execute( 'updateMass', { id: this._physijs.id, mass: mass } ); - } - }); - - // Physijs.Mesh.applyCentralImpulse - Physijs.Mesh.prototype.applyCentralImpulse = function ( force ) { - if ( this.world ) { - this.world.execute( 'applyCentralImpulse', { id: this._physijs.id, x: force.x, y: force.y, z: force.z } ); + // Physijs.Mesh.applyForce + applyForce( force, offset ) { + if ( this.world ) { + this.world.execute( 'applyForce', { id: this._physijs.id, force_x: force.x, force_y : force.y, force_z : force.z, x: offset.x, y: offset.y, z: offset.z } ); + } } - }; - // Physijs.Mesh.applyImpulse - Physijs.Mesh.prototype.applyImpulse = function ( force, offset ) { - if ( this.world ) { - this.world.execute( 'applyImpulse', { id: this._physijs.id, impulse_x: force.x, impulse_y: force.y, impulse_z: force.z, x: offset.x, y: offset.y, z: offset.z } ); + // Physijs.Mesh.getAngularVelocity + getAngularVelocity() { + return this._physijs.angularVelocity; } - }; - // Physijs.Mesh.applyTorque - Physijs.Mesh.prototype.applyTorque = function ( force ) { - if ( this.world ) { - this.world.execute( 'applyTorque', { id: this._physijs.id, torque_x: force.x, torque_y: force.y, torque_z: force.z } ); + // Physijs.Mesh.setAngularVelocity + setAngularVelocity( velocity ) { + if ( this.world ) { + this.world.execute( 'setAngularVelocity', { id: this._physijs.id, x: velocity.x, y: velocity.y, z: velocity.z } ); + } } - }; - // Physijs.Mesh.applyCentralForce - Physijs.Mesh.prototype.applyCentralForce = function ( force ) { - if ( this.world ) { - this.world.execute( 'applyCentralForce', { id: this._physijs.id, x: force.x, y: force.y, z: force.z } ); + // Physijs.Mesh.getLinearVelocity + getLinearVelocity() { + return this._physijs.linearVelocity; } - }; - // Physijs.Mesh.applyForce - Physijs.Mesh.prototype.applyForce = function ( force, offset ) { - if ( this.world ) { - this.world.execute( 'applyForce', { id: this._physijs.id, force_x: force.x, force_y : force.y, force_z : force.z, x: offset.x, y: offset.y, z: offset.z } ); + // Physijs.Mesh.setLinearVelocity + setLinearVelocity( velocity ) { + if ( this.world ) { + this.world.execute( 'setLinearVelocity', { id: this._physijs.id, x: velocity.x, y: velocity.y, z: velocity.z } ); + } } - }; - - // Physijs.Mesh.getAngularVelocity - Physijs.Mesh.prototype.getAngularVelocity = function () { - return this._physijs.angularVelocity; - }; - // Physijs.Mesh.setAngularVelocity - Physijs.Mesh.prototype.setAngularVelocity = function ( velocity ) { - if ( this.world ) { - this.world.execute( 'setAngularVelocity', { id: this._physijs.id, x: velocity.x, y: velocity.y, z: velocity.z } ); + // Physijs.Mesh.setAngularFactor + setAngularFactor( factor ) { + if ( this.world ) { + this.world.execute( 'setAngularFactor', { id: this._physijs.id, x: factor.x, y: factor.y, z: factor.z } ); + } } - }; - // Physijs.Mesh.getLinearVelocity - Physijs.Mesh.prototype.getLinearVelocity = function () { - return this._physijs.linearVelocity; - }; - - // Physijs.Mesh.setLinearVelocity - Physijs.Mesh.prototype.setLinearVelocity = function ( velocity ) { - if ( this.world ) { - this.world.execute( 'setLinearVelocity', { id: this._physijs.id, x: velocity.x, y: velocity.y, z: velocity.z } ); + // Physijs.Mesh.setLinearFactor + setLinearFactor( factor ) { + if ( this.world ) { + this.world.execute( 'setLinearFactor', { id: this._physijs.id, x: factor.x, y: factor.y, z: factor.z } ); + } } - }; - // Physijs.Mesh.setAngularFactor - Physijs.Mesh.prototype.setAngularFactor = function ( factor ) { - if ( this.world ) { - this.world.execute( 'setAngularFactor', { id: this._physijs.id, x: factor.x, y: factor.y, z: factor.z } ); + // Physijs.Mesh.setDamping + setDamping( linear, angular ) { + if ( this.world ) { + this.world.execute( 'setDamping', { id: this._physijs.id, linear: linear, angular: angular } ); + } } - }; - // Physijs.Mesh.setLinearFactor - Physijs.Mesh.prototype.setLinearFactor = function ( factor ) { - if ( this.world ) { - this.world.execute( 'setLinearFactor', { id: this._physijs.id, x: factor.x, y: factor.y, z: factor.z } ); + // Physijs.Mesh.setCcdMotionThreshold + setCcdMotionThreshold( threshold ) { + if ( this.world ) { + this.world.execute( 'setCcdMotionThreshold', { id: this._physijs.id, threshold: threshold } ); + } } - }; - // Physijs.Mesh.setDamping - Physijs.Mesh.prototype.setDamping = function ( linear, angular ) { - if ( this.world ) { - this.world.execute( 'setDamping', { id: this._physijs.id, linear: linear, angular: angular } ); + // Physijs.Mesh.setCcdSweptSphereRadius + setCcdSweptSphereRadius( radius ) { + if ( this.world ) { + this.world.execute( 'setCcdSweptSphereRadius', { id: this._physijs.id, radius: radius } ); + } } - }; + } - // Physijs.Mesh.setCcdMotionThreshold - Physijs.Mesh.prototype.setCcdMotionThreshold = function ( threshold ) { - if ( this.world ) { - this.world.execute( 'setCcdMotionThreshold', { id: this._physijs.id, threshold: threshold } ); - } - }; + Physijs.Mesh = Mesh; - // Physijs.Mesh.setCcdSweptSphereRadius - Physijs.Mesh.prototype.setCcdSweptSphereRadius = function ( radius ) { - if ( this.world ) { - this.world.execute( 'setCcdSweptSphereRadius', { id: this._physijs.id, radius: radius } ); - } - }; + // Physijs.PlaneMesh + class PlaneMesh extends Physijs.Mesh { + constructor ( geometry, material, mass ) { + super( geometry, material, mass ); - // Physijs.PlaneMesh - Physijs.PlaneMesh = function ( geometry, material, mass ) { - var width, height; + var width, height; - Physijs.Mesh.call( this, geometry, material, mass ); + if ( !geometry.boundingBox ) { + geometry.computeBoundingBox(); + } - if ( !geometry.boundingBox ) { - geometry.computeBoundingBox(); - } + width = geometry.boundingBox.max.x - geometry.boundingBox.min.x; + height = geometry.boundingBox.max.y - geometry.boundingBox.min.y; - width = geometry.boundingBox.max.x - geometry.boundingBox.min.x; - height = geometry.boundingBox.max.y - geometry.boundingBox.min.y; + this._physijs.type = 'plane'; + this._physijs.normal = geometry.faces[0].normal.clone(); + this._physijs.mass = (typeof mass === 'undefined') ? width * height : mass; + } + } - this._physijs.type = 'plane'; - this._physijs.normal = geometry.faces[0].normal.clone(); - this._physijs.mass = (typeof mass === 'undefined') ? width * height : mass; - }; - Physijs.PlaneMesh.prototype = new Physijs.Mesh; - Physijs.PlaneMesh.prototype.constructor = Physijs.PlaneMesh; + Physijs.PlaneMesh = PlaneMesh; // Physijs.HeightfieldMesh - Physijs.HeightfieldMesh = function ( geometry, material, mass, xdiv, ydiv) { - Physijs.Mesh.call( this, geometry, material, mass ); + class HeightfieldMesh extends Physijs.Mesh { + constructor( geometry, material, mass, xdiv, ydiv) { + Physijs.Mesh.call( this, geometry, material, mass ); + + this._physijs.type = 'heightfield'; + this._physijs.xsize = geometry.boundingBox.max.x - geometry.boundingBox.min.x; + this._physijs.ysize = geometry.boundingBox.max.y - geometry.boundingBox.min.y; + this._physijs.xpts = (typeof xdiv === 'undefined') ? Math.sqrt(geometry.vertices.length) : xdiv + 1; + this._physijs.ypts = (typeof ydiv === 'undefined') ? Math.sqrt(geometry.vertices.length) : ydiv + 1; + // note - this assumes our plane geometry is square, unless we pass in specific xdiv and ydiv + this._physijs.absMaxHeight = Math.max(geometry.boundingBox.max.z,Math.abs(geometry.boundingBox.min.z)); - this._physijs.type = 'heightfield'; - this._physijs.xsize = geometry.boundingBox.max.x - geometry.boundingBox.min.x; - this._physijs.ysize = geometry.boundingBox.max.y - geometry.boundingBox.min.y; - this._physijs.xpts = (typeof xdiv === 'undefined') ? Math.sqrt(geometry.vertices.length) : xdiv + 1; - this._physijs.ypts = (typeof ydiv === 'undefined') ? Math.sqrt(geometry.vertices.length) : ydiv + 1; - // note - this assumes our plane geometry is square, unless we pass in specific xdiv and ydiv - this._physijs.absMaxHeight = Math.max(geometry.boundingBox.max.z,Math.abs(geometry.boundingBox.min.z)); + var points = []; - var points = []; + var a, b; + for ( var i = 0; i < geometry.vertices.length; i++ ) { - var a, b; - for ( var i = 0; i < geometry.vertices.length; i++ ) { + a = i % this._physijs.xpts; + b = Math.round( ( i / this._physijs.xpts ) - ( (i % this._physijs.xpts) / this._physijs.xpts ) ); + points[i] = geometry.vertices[ a + ( ( this._physijs.ypts - b - 1 ) * this._physijs.ypts ) ].z; - a = i % this._physijs.xpts; - b = Math.round( ( i / this._physijs.xpts ) - ( (i % this._physijs.xpts) / this._physijs.xpts ) ); - points[i] = geometry.vertices[ a + ( ( this._physijs.ypts - b - 1 ) * this._physijs.ypts ) ].z; + //points[i] = geometry.vertices[i]; + } - //points[i] = geometry.vertices[i]; + this._physijs.points = points; } + } - this._physijs.points = points; - }; - Physijs.HeightfieldMesh.prototype = new Physijs.Mesh; - Physijs.HeightfieldMesh.prototype.constructor = Physijs.HeightfieldMesh; + Physijs.HeightfieldMesh = HeightfieldMesh; // Physijs.BoxMesh - Physijs.BoxMesh = function( geometry, material, mass ) { - var width, height, depth; + class BoxMesh extends Physijs.Mesh { + constructor( geometry, material, mass ) { + super( geometry, material, mass ); - Physijs.Mesh.call( this, geometry, material, mass ); + var width, height, depth; - if ( !geometry.boundingBox ) { - geometry.computeBoundingBox(); - } + if ( !geometry.boundingBox ) { + geometry.computeBoundingBox(); + } - width = geometry.boundingBox.max.x - geometry.boundingBox.min.x; - height = geometry.boundingBox.max.y - geometry.boundingBox.min.y; - depth = geometry.boundingBox.max.z - geometry.boundingBox.min.z; + width = geometry.boundingBox.max.x - geometry.boundingBox.min.x; + height = geometry.boundingBox.max.y - geometry.boundingBox.min.y; + depth = geometry.boundingBox.max.z - geometry.boundingBox.min.z; - this._physijs.type = 'box'; - this._physijs.width = width; - this._physijs.height = height; - this._physijs.depth = depth; - this._physijs.mass = (typeof mass === 'undefined') ? width * height * depth : mass; - }; - Physijs.BoxMesh.prototype = new Physijs.Mesh; - Physijs.BoxMesh.prototype.constructor = Physijs.BoxMesh; + this._physijs.type = 'box'; + this._physijs.width = width; + this._physijs.height = height; + this._physijs.depth = depth; + this._physijs.mass = (typeof mass === 'undefined') ? width * height * depth : mass; + } + } + Physijs.BoxMesh = BoxMesh; // Physijs.SphereMesh - Physijs.SphereMesh = function( geometry, material, mass ) { - Physijs.Mesh.call( this, geometry, material, mass ); + class SphereMesh extends Physijs.Mesh { + constructor( geometry, material, mass ) { + super( geometry, material, mass ); - if ( !geometry.boundingSphere ) { - geometry.computeBoundingSphere(); - } + if ( !geometry.boundingSphere ) { + geometry.computeBoundingSphere(); + } - this._physijs.type = 'sphere'; - this._physijs.radius = geometry.boundingSphere.radius; - this._physijs.mass = (typeof mass === 'undefined') ? (4/3) * Math.PI * Math.pow(this._physijs.radius, 3) : mass; - }; - Physijs.SphereMesh.prototype = new Physijs.Mesh; - Physijs.SphereMesh.prototype.constructor = Physijs.SphereMesh; + this._physijs.type = 'sphere'; + this._physijs.radius = geometry.boundingSphere.radius; + this._physijs.mass = (typeof mass === 'undefined') ? (4/3) * Math.PI * Math.pow(this._physijs.radius, 3) : mass; + } + } + Physijs.SphereMesh = SphereMesh; // Physijs.CylinderMesh - Physijs.CylinderMesh = function( geometry, material, mass ) { - var width, height, depth; + class CylinderMesh extends Physijs.Mesh { + constructor( geometry, material, mass ) { + var width, height, depth; - Physijs.Mesh.call( this, geometry, material, mass ); + super( geometry, material, mass ); - if ( !geometry.boundingBox ) { - geometry.computeBoundingBox(); - } + if ( !geometry.boundingBox ) { + geometry.computeBoundingBox(); + } - width = geometry.boundingBox.max.x - geometry.boundingBox.min.x; - height = geometry.boundingBox.max.y - geometry.boundingBox.min.y; - depth = geometry.boundingBox.max.z - geometry.boundingBox.min.z; + width = geometry.boundingBox.max.x - geometry.boundingBox.min.x; + height = geometry.boundingBox.max.y - geometry.boundingBox.min.y; + depth = geometry.boundingBox.max.z - geometry.boundingBox.min.z; - this._physijs.type = 'cylinder'; - this._physijs.width = width; - this._physijs.height = height; - this._physijs.depth = depth; - this._physijs.mass = (typeof mass === 'undefined') ? width * height * depth : mass; - }; - Physijs.CylinderMesh.prototype = new Physijs.Mesh; - Physijs.CylinderMesh.prototype.constructor = Physijs.CylinderMesh; + this._physijs.type = 'cylinder'; + this._physijs.width = width; + this._physijs.height = height; + this._physijs.depth = depth; + this._physijs.mass = (typeof mass === 'undefined') ? width * height * depth : mass; + } + } + Physijs.CylinderMesh = CylinderMesh; // Physijs.CapsuleMesh - Physijs.CapsuleMesh = function( geometry, material, mass ) { - var width, height, depth; + class CapsuleMesh extends Physijs.Mesh { + constructor( geometry, material, mass ) { + var width, height, depth; - Physijs.Mesh.call( this, geometry, material, mass ); + super( geometry, material, mass ); - if ( !geometry.boundingBox ) { - geometry.computeBoundingBox(); - } + if ( !geometry.boundingBox ) { + geometry.computeBoundingBox(); + } - width = geometry.boundingBox.max.x - geometry.boundingBox.min.x; - height = geometry.boundingBox.max.y - geometry.boundingBox.min.y; - depth = geometry.boundingBox.max.z - geometry.boundingBox.min.z; + width = geometry.boundingBox.max.x - geometry.boundingBox.min.x; + height = geometry.boundingBox.max.y - geometry.boundingBox.min.y; + depth = geometry.boundingBox.max.z - geometry.boundingBox.min.z; - this._physijs.type = 'capsule'; - this._physijs.radius = Math.max(width / 2, depth / 2); - this._physijs.height = height; - this._physijs.mass = (typeof mass === 'undefined') ? width * height * depth : mass; - }; - Physijs.CapsuleMesh.prototype = new Physijs.Mesh; - Physijs.CapsuleMesh.prototype.constructor = Physijs.CapsuleMesh; + this._physijs.type = 'capsule'; + this._physijs.radius = Math.max(width / 2, depth / 2); + this._physijs.height = height; + this._physijs.mass = (typeof mass === 'undefined') ? width * height * depth : mass; + } + } + Physijs.CapsuleMesh = CapsuleMesh; // Physijs.ConeMesh - Physijs.ConeMesh = function( geometry, material, mass ) { - var width, height, depth; + class ConeMesh extends Physijs.Mesh { + constructor( geometry, material, mass ) { + var width, height, depth; - Physijs.Mesh.call( this, geometry, material, mass ); + super( geometry, material, mass ); - if ( !geometry.boundingBox ) { - geometry.computeBoundingBox(); - } + if ( !geometry.boundingBox ) { + geometry.computeBoundingBox(); + } - width = geometry.boundingBox.max.x - geometry.boundingBox.min.x; - height = geometry.boundingBox.max.y - geometry.boundingBox.min.y; + width = geometry.boundingBox.max.x - geometry.boundingBox.min.x; + height = geometry.boundingBox.max.y - geometry.boundingBox.min.y; - this._physijs.type = 'cone'; - this._physijs.radius = width / 2; - this._physijs.height = height; - this._physijs.mass = (typeof mass === 'undefined') ? width * height : mass; - }; - Physijs.ConeMesh.prototype = new Physijs.Mesh; - Physijs.ConeMesh.prototype.constructor = Physijs.ConeMesh; + this._physijs.type = 'cone'; + this._physijs.radius = width / 2; + this._physijs.height = height; + this._physijs.mass = (typeof mass === 'undefined') ? width * height : mass; + } + } + Physijs.ConeMesh = ConeMesh; // Physijs.ConcaveMesh - Physijs.ConcaveMesh = function( geometry, material, mass ) { - var i, - width, height, depth, - vertices, face, triangles = []; + class ConcaveMesh extends Physijs.Mesh { + constructor( geometry, material, mass ) { + var i, + width, height, depth, + vertices, face, triangles = []; - Physijs.Mesh.call( this, geometry, material, mass ); + super( geometry, material, mass ); - if ( !geometry.boundingBox ) { - geometry.computeBoundingBox(); - } + if ( !geometry.boundingBox ) { + geometry.computeBoundingBox(); + } - vertices = geometry.vertices; + vertices = geometry.vertices; - for ( i = 0; i < geometry.faces.length; i++ ) { - face = geometry.faces[i]; - if ( face instanceof THREE.Face3) { + for ( i = 0; i < geometry.faces.length; i++ ) { + face = geometry.faces[i]; + if ( face instanceof THREE.Face3) { - triangles.push([ - { x: vertices[face.a].x, y: vertices[face.a].y, z: vertices[face.a].z }, - { x: vertices[face.b].x, y: vertices[face.b].y, z: vertices[face.b].z }, - { x: vertices[face.c].x, y: vertices[face.c].y, z: vertices[face.c].z } - ]); + triangles.push([ + { x: vertices[face.a].x, y: vertices[face.a].y, z: vertices[face.a].z }, + { x: vertices[face.b].x, y: vertices[face.b].y, z: vertices[face.b].z }, + { x: vertices[face.c].x, y: vertices[face.c].y, z: vertices[face.c].z } + ]); - } else if ( face instanceof THREE.Face4 ) { + } else if ( face instanceof THREE.Face4 ) { - triangles.push([ - { x: vertices[face.a].x, y: vertices[face.a].y, z: vertices[face.a].z }, - { x: vertices[face.b].x, y: vertices[face.b].y, z: vertices[face.b].z }, - { x: vertices[face.d].x, y: vertices[face.d].y, z: vertices[face.d].z } - ]); - triangles.push([ - { x: vertices[face.b].x, y: vertices[face.b].y, z: vertices[face.b].z }, - { x: vertices[face.c].x, y: vertices[face.c].y, z: vertices[face.c].z }, - { x: vertices[face.d].x, y: vertices[face.d].y, z: vertices[face.d].z } - ]); + triangles.push([ + { x: vertices[face.a].x, y: vertices[face.a].y, z: vertices[face.a].z }, + { x: vertices[face.b].x, y: vertices[face.b].y, z: vertices[face.b].z }, + { x: vertices[face.d].x, y: vertices[face.d].y, z: vertices[face.d].z } + ]); + triangles.push([ + { x: vertices[face.b].x, y: vertices[face.b].y, z: vertices[face.b].z }, + { x: vertices[face.c].x, y: vertices[face.c].y, z: vertices[face.c].z }, + { x: vertices[face.d].x, y: vertices[face.d].y, z: vertices[face.d].z } + ]); + } } - } - width = geometry.boundingBox.max.x - geometry.boundingBox.min.x; - height = geometry.boundingBox.max.y - geometry.boundingBox.min.y; - depth = geometry.boundingBox.max.z - geometry.boundingBox.min.z; + width = geometry.boundingBox.max.x - geometry.boundingBox.min.x; + height = geometry.boundingBox.max.y - geometry.boundingBox.min.y; + depth = geometry.boundingBox.max.z - geometry.boundingBox.min.z; - this._physijs.type = 'concave'; - this._physijs.triangles = triangles; - this._physijs.mass = (typeof mass === 'undefined') ? width * height * depth : mass; - }; - Physijs.ConcaveMesh.prototype = new Physijs.Mesh; - Physijs.ConcaveMesh.prototype.constructor = Physijs.ConcaveMesh; + this._physijs.type = 'concave'; + this._physijs.triangles = triangles; + this._physijs.mass = (typeof mass === 'undefined') ? width * height * depth : mass; + } + } + Physijs.ConcaveMesh = ConcaveMesh; // Physijs.ConvexMesh - Physijs.ConvexMesh = function( geometry, material, mass ) { - var i, - width, height, depth, - points = []; + class ConvexMesh extends Physijs.Mesh { + constructor( geometry, material, mass ) { + var i, + width, height, depth, + points = []; - Physijs.Mesh.call( this, geometry, material, mass ); + super( geometry, material, mass ); - if ( !geometry.boundingBox ) { - geometry.computeBoundingBox(); - } + if ( !geometry.boundingBox ) { + geometry.computeBoundingBox(); + } - for ( i = 0; i < geometry.vertices.length; i++ ) { - points.push({ - x: geometry.vertices[i].x, - y: geometry.vertices[i].y, - z: geometry.vertices[i].z - }); - } + for ( i = 0; i < geometry.vertices.length; i++ ) { + points.push({ + x: geometry.vertices[i].x, + y: geometry.vertices[i].y, + z: geometry.vertices[i].z + }); + } - width = geometry.boundingBox.max.x - geometry.boundingBox.min.x; - height = geometry.boundingBox.max.y - geometry.boundingBox.min.y; - depth = geometry.boundingBox.max.z - geometry.boundingBox.min.z; + width = geometry.boundingBox.max.x - geometry.boundingBox.min.x; + height = geometry.boundingBox.max.y - geometry.boundingBox.min.y; + depth = geometry.boundingBox.max.z - geometry.boundingBox.min.z; - this._physijs.type = 'convex'; - this._physijs.points = points; - this._physijs.mass = (typeof mass === 'undefined') ? width * height * depth : mass; - }; - Physijs.ConvexMesh.prototype = new Physijs.Mesh; - Physijs.ConvexMesh.prototype.constructor = Physijs.ConvexMesh; + this._physijs.type = 'convex'; + this._physijs.points = points; + this._physijs.mass = (typeof mass === 'undefined') ? width * height * depth : mass; + } + } + Physijs.ConvexMesh = ConvexMesh; // Physijs.Vehicle - Physijs.Vehicle = function( mesh, tuning ) { - tuning = tuning || new Physijs.VehicleTuning; - this.mesh = mesh; - this.wheels = []; - this._physijs = { - id: getObjectId(), - rigidBody: mesh._physijs.id, - suspension_stiffness: tuning.suspension_stiffness, - suspension_compression: tuning.suspension_compression, - suspension_damping: tuning.suspension_damping, - max_suspension_travel: tuning.max_suspension_travel, - friction_slip: tuning.friction_slip, - max_suspension_force: tuning.max_suspension_force - }; - }; - Physijs.Vehicle.prototype.addWheel = function( wheel_geometry, wheel_material, connection_point, wheel_direction, wheel_axle, suspension_rest_length, wheel_radius, is_front_wheel, tuning ) { - var wheel = new THREE.Mesh( wheel_geometry, wheel_material ); - wheel.castShadow = wheel.receiveShadow = true; - wheel.position.copy( wheel_direction ).multiplyScalar( suspension_rest_length / 100 ).add( connection_point ); - this.world.add( wheel ); - this.wheels.push( wheel ); - - this.world.execute( 'addWheel', { - id: this._physijs.id, - connection_point: { x: connection_point.x, y: connection_point.y, z: connection_point.z }, - wheel_direction: { x: wheel_direction.x, y: wheel_direction.y, z: wheel_direction.z }, - wheel_axle: { x: wheel_axle.x, y: wheel_axle.y, z: wheel_axle.z }, - suspension_rest_length: suspension_rest_length, - wheel_radius: wheel_radius, - is_front_wheel: is_front_wheel, - tuning: tuning - }); - }; - Physijs.Vehicle.prototype.setSteering = function( amount, wheel ) { - if ( wheel !== undefined && this.wheels[ wheel ] !== undefined ) { - this.world.execute( 'setSteering', { id: this._physijs.id, wheel: wheel, steering: amount } ); - } else if ( this.wheels.length > 0 ) { - for ( var i = 0; i < this.wheels.length; i++ ) { - this.world.execute( 'setSteering', { id: this._physijs.id, wheel: i, steering: amount } ); - } + class Vehicle { + constructor( mesh, tuning ) { + tuning = tuning || new Physijs.VehicleTuning; + this.mesh = mesh; + this.wheels = []; + this._physijs = { + id: getObjectId(), + rigidBody: mesh._physijs.id, + suspension_stiffness: tuning.suspension_stiffness, + suspension_compression: tuning.suspension_compression, + suspension_damping: tuning.suspension_damping, + max_suspension_travel: tuning.max_suspension_travel, + friction_slip: tuning.friction_slip, + max_suspension_force: tuning.max_suspension_force + }; } - }; - Physijs.Vehicle.prototype.setBrake = function( amount, wheel ) { - if ( wheel !== undefined && this.wheels[ wheel ] !== undefined ) { - this.world.execute( 'setBrake', { id: this._physijs.id, wheel: wheel, brake: amount } ); - } else if ( this.wheels.length > 0 ) { - for ( var i = 0; i < this.wheels.length; i++ ) { - this.world.execute( 'setBrake', { id: this._physijs.id, wheel: i, brake: amount } ); + + addWheel( wheel_geometry, wheel_material, connection_point, wheel_direction, wheel_axle, suspension_rest_length, wheel_radius, is_front_wheel, tuning ) { + var wheel = new THREE.Mesh( wheel_geometry, wheel_material ); + wheel.castShadow = wheel.receiveShadow = true; + wheel.position.copy( wheel_direction ).multiplyScalar( suspension_rest_length / 100 ).add( connection_point ); + this.world.add( wheel ); + this.wheels.push( wheel ); + + this.world.execute( 'addWheel', { + id: this._physijs.id, + connection_point: { x: connection_point.x, y: connection_point.y, z: connection_point.z }, + wheel_direction: { x: wheel_direction.x, y: wheel_direction.y, z: wheel_direction.z }, + wheel_axle: { x: wheel_axle.x, y: wheel_axle.y, z: wheel_axle.z }, + suspension_rest_length: suspension_rest_length, + wheel_radius: wheel_radius, + is_front_wheel: is_front_wheel, + tuning: tuning + }); + } + + setSteering( amount, wheel ) { + if ( wheel !== undefined && this.wheels[ wheel ] !== undefined ) { + this.world.execute( 'setSteering', { id: this._physijs.id, wheel: wheel, steering: amount } ); + } else if ( this.wheels.length > 0 ) { + for ( var i = 0; i < this.wheels.length; i++ ) { + this.world.execute( 'setSteering', { id: this._physijs.id, wheel: i, steering: amount } ); + } } } - }; - Physijs.Vehicle.prototype.applyEngineForce = function( amount, wheel ) { - if ( wheel !== undefined && this.wheels[ wheel ] !== undefined ) { - this.world.execute( 'applyEngineForce', { id: this._physijs.id, wheel: wheel, force: amount } ); - } else if ( this.wheels.length > 0 ) { - for ( var i = 0; i < this.wheels.length; i++ ) { - this.world.execute( 'applyEngineForce', { id: this._physijs.id, wheel: i, force: amount } ); + + setBrake( amount, wheel ) { + if ( wheel !== undefined && this.wheels[ wheel ] !== undefined ) { + this.world.execute( 'setBrake', { id: this._physijs.id, wheel: wheel, brake: amount } ); + } else if ( this.wheels.length > 0 ) { + for ( var i = 0; i < this.wheels.length; i++ ) { + this.world.execute( 'setBrake', { id: this._physijs.id, wheel: i, brake: amount } ); + } + } + }; + + applyEngineForce( amount, wheel ) { + if ( wheel !== undefined && this.wheels[ wheel ] !== undefined ) { + this.world.execute( 'applyEngineForce', { id: this._physijs.id, wheel: wheel, force: amount } ); + } else if ( this.wheels.length > 0 ) { + for ( var i = 0; i < this.wheels.length; i++ ) { + this.world.execute( 'applyEngineForce', { id: this._physijs.id, wheel: i, force: amount } ); + } } } - }; + } + + Physijs.Vehicle = Vehicle; // Physijs.VehicleTuning Physijs.VehicleTuning = function( suspension_stiffness, suspension_compression, suspension_damping, max_suspension_travel, friction_slip, max_suspension_force ) {