diff --git a/CONTRIBUTORS.md b/CONTRIBUTORS.md
index fda65cb32..5807d1e1b 100644
--- a/CONTRIBUTORS.md
+++ b/CONTRIBUTORS.md
@@ -243,7 +243,8 @@ All definitions files include a header with the author and editors, so at some p
* [Marked](https://github.com/chjj/marked) (by [William Orr](https://github.com/worr))
* [MathJax](https://github.com/mathjax/MathJax) (by [Roland Zwaga](https://github.com/rolandzwaga))
* [mCustomScrollbar](https://github.com/malihu/malihu-custom-scrollbar-plugin) (by [Sarah Williams](https://github.com/flurg))
-* [Meteor](https://www.meteor.com) (by [Dave Allen](https://github.com/fullflavedave))
+* [Meteor](https://www.meteor.com) (by [Dave Allen](https://github.com/fullflavedave))
+* [md5.js](http://labs.cybozu.co.jp/blog/mitsunari/2007/07/md5js_1.html) (by [MIZUNE Pine](https://github.com/pine613))
* [Microsoft Ajax](http://msdn.microsoft.com/en-us/library/ee341002(v=vs.100).aspx) (by [Patrick Magee](https://github.com/pjmagee))
* [Microsoft Live Connect](http://msdn.microsoft.com/en-us/library/live/hh243643.aspx) (by [John Vilk](https://github.com/jvilk))
* [Minimatch](https://github.com/isaacs/minimatch) (by [vvakame](https://github.com/vvakame))
@@ -290,6 +291,7 @@ All definitions files include a header with the author and editors, so at some p
* [Persona](http://www.mozilla.org/en-US/persona) (by [James Frasca](https://github.com/Nycto))
* [PhantomJS](http://phantomjs.org) (by [Jed Hunsaker](https://github.com/jedhunsaker))
* [PhoneGap](http://phonegap.com) (by [Boris Yankov](https://github.com/borisyankov))
+* [Physijs](http://chandlerprall.github.io/Physijs/) (by [gyoh_k](https://github.com/gyohk))
* [PixiJS](https://github.com/GoodBoyDigital/pixi.js) (by [Pedro Casaubon](https://github.com/xperiments))
* [Platform](https://github.com/bestiejs/platform.js) (by [Jake Hickman](https://github.com/JakeH))
* [PouchDB](http://pouchdb.com) (by [Bill Sears](https://github.com/MrBigDog2U/))
diff --git a/md5/md5-test.ts b/md5/md5-test.ts
new file mode 100644
index 000000000..036ad9c2a
--- /dev/null
+++ b/md5/md5-test.ts
@@ -0,0 +1,9 @@
+///
+
+var hash: string;
+hash = CybozuLabs.MD5.calc("abc");
+hash = CybozuLabs.MD5.calc("abc", CybozuLabs.MD5.BY_ASCII);
+hash = CybozuLabs.MD5.calc("abc", CybozuLabs.MD5.BY_UTF16);
+
+var version: string;
+version = CybozuLabs.MD5.VERSION;
\ No newline at end of file
diff --git a/md5/md5.d.ts b/md5/md5.d.ts
new file mode 100644
index 000000000..207a30699
--- /dev/null
+++ b/md5/md5.d.ts
@@ -0,0 +1,11 @@
+// Type definitions for CybozuLabs.MD5
+// Project: http://labs.cybozu.co.jp/blog/mitsunari/2007/07/md5js_1.html
+// Definitions by: MIZUNE Pine
+// Definitions: https://github.com/borisyankov/DefinitelyTyped
+
+declare module CybozuLabs.MD5 {
+ var VERSION: string;
+ var BY_ASCII: number;
+ var BY_UTF16: number;
+ function calc(str: string, option?: number): string;
+}
\ No newline at end of file
diff --git a/physijs/physijs-tests.ts b/physijs/physijs-tests.ts
new file mode 100644
index 000000000..35591c12d
--- /dev/null
+++ b/physijs/physijs-tests.ts
@@ -0,0 +1,15 @@
+/////////////////////////////////////////////////////////////
+// https://github.com/chandlerprall/Physijs/tree/master/examples
+//////////////////////////////////////////////////////////////
+
+///
+///
+///
+///
+///
+///
+///
+///
+///
+///
+///
diff --git a/physijs/physijs-tests.ts.tscparams b/physijs/physijs-tests.ts.tscparams
new file mode 100644
index 000000000..3b6942a9d
--- /dev/null
+++ b/physijs/physijs-tests.ts.tscparams
@@ -0,0 +1,2 @@
+""
+
diff --git a/physijs/physijs.d.ts b/physijs/physijs.d.ts
new file mode 100644
index 000000000..8a63b5ad4
--- /dev/null
+++ b/physijs/physijs.d.ts
@@ -0,0 +1,250 @@
+// Type definitions for Physijs
+// Project: http://chandlerprall.github.io/Physijs/
+// Definitions by: Satoru Kimura
+// Definitions: https://github.com/borisyankov/DefinitelyTyped
+
+
+///
+
+declare module Physijs {
+ export function noConflict():Object;
+ export function createMaterial(material: THREE.Material, friction?: number, restitution?: number): Material;
+
+ export interface Material extends THREE.Material{
+ _physijs: {
+ id: number;
+ friction: number;
+ restriction: number
+ };
+ }
+
+ export interface Constraint {
+ getDefinition(): any;
+ }
+
+ export interface PointConstraintDefinition {
+ type: string;
+ id: number;
+ objecta: THREE.Object3D;
+ objectb: THREE.Object3D;
+ positiona: THREE.Vector3;
+ positionb: THREE.Vector3;
+ }
+
+ export class PointConstraint implements Constraint {
+ constructor(objecta: THREE.Object3D, objectb: THREE.Object3D, position?: THREE.Vector3);
+
+ getDefinition(): PointConstraintDefinition;
+ }
+
+ export interface HingeConstraintDefinition {
+ type: string;
+ id: number;
+ objecta: THREE.Object3D;
+ objectb: THREE.Object3D;
+ positiona: THREE.Vector3;
+ positionb: THREE.Vector3;
+ axis: THREE.Vector3;
+ }
+
+ export class HingeConstraint implements Constraint {
+ constructor(objecta: THREE.Object3D, objectb: THREE.Object3D, position: THREE.Vector3, axis?: THREE.Vector3);
+
+ getDefinition(): HingeConstraintDefinition;
+ setLimits( low: number, high: number, bias_factor: number, relaxation_factor: number ): void;
+ enableAngularMotor( velocity: number, acceleration: number ): void;
+ disableMotor(): void;
+ }
+
+ export interface SliderConstraintDefinition {
+ type: string;
+ id: number;
+ objecta: THREE.Object3D;
+ objectb: THREE.Object3D;
+ positiona: THREE.Vector3;
+ positionb: THREE.Vector3;
+ axis: THREE.Vector3;
+ }
+
+ export class SliderConstraint implements Constraint {
+ constructor(objecta: THREE.Object3D, objectb: THREE.Object3D, position: THREE.Vector3, axis?: THREE.Vector3);
+
+ getDefinition(): SliderConstraintDefinition;
+ setLimits( lin_lower: number, lin_upper: number, ang_lower: number, ang_upper: number ): void;
+ setRestitution( linear: number, angular: number ): void;
+ enableLinearMotor( velocity: number, acceleration: number): void;
+ disableLinearMotor(): void;
+ enableAngularMotor( velocity: number, acceleration: number ): void;
+ disableAngularMotor(): void;
+ }
+
+ export interface ConeTwistConstraintDefinition {
+ type: string;
+ id: number;
+ objecta: THREE.Object3D;
+ objectb: THREE.Object3D;
+ positiona: THREE.Vector3;
+ positionb: THREE.Vector3;
+ axisa: THREE.Vector3;
+ axisb: THREE.Vector3;
+ }
+
+ export class ConeTwistConstraint implements Constraint {
+ constructor(objecta: THREE.Object3D, objectb: THREE.Object3D, position: THREE.Vector3);
+
+ getDefinition(): ConeTwistConstraintDefinition;
+ setLimit( x: number, y: number, z: number ): void;
+ enableMotor(): void;
+ setMaxMotorImpulse( max_impulse: number ): void;
+ setMotorTarget( target: THREE.Vector3 ): void;
+ setMotorTarget( target: THREE.Euler ): void;
+ setMotorTarget( target: THREE.Matrix4 ): void;
+ disableMotor(): void;
+
+ }
+
+ export interface DOFConstraintDefinition {
+ type: string;
+ id: number;
+ objecta: THREE.Object3D;
+ objectb: THREE.Object3D;
+ positiona: THREE.Vector3;
+ positionb: THREE.Vector3;
+ axisa: THREE.Vector3;
+ axisb: THREE.Vector3;
+ }
+
+ export class DOFConstraint implements Constraint {
+ constructor(objecta: THREE.Object3D, objectb: THREE.Object3D, position?: THREE.Vector3);
+
+ getDefinition(): DOFConstraintDefinition;
+ setLinearLowerLimit(limit: THREE.Vector3): void;
+ setLinearUpperLimit(limit: THREE.Vector3): void;
+ setAngularLowerLimit(limit: THREE.Vector3): void;
+ setAngularUpperLimit(limit: THREE.Vector3): void;
+ enableAngularMotor( which: number ): void;
+ configureAngularMotor( which: number, low_angle: number, high_angle: number, velocity: number, max_force: number ): void;
+ disableAngularMotor( which: number ): void;
+ }
+ export var scripts: {
+ worker: string;
+ ammo: string;
+ };
+
+ export interface SceneParameters {
+ ammo?: string;
+ fixedTimeStep?: number;
+ rateLimit?: boolean;
+ }
+
+ export class Scene extends THREE.Scene {
+ constructor(param?: SceneParameters);
+
+ addConstraint(constraint:Constraint, show_marker?:boolean):void;
+ onSimulationResume():void;
+ removeConstraint(constraint:Constraint):void;
+ execute(cmd:string, params:any):void;
+ add(object:THREE.Object3D):void;
+ remove(object:THREE.Object3D):void;
+ setFixedTimeStep(fixedTimeStep:number):void;
+ setGravity(gravity:number):void;
+ simulate(timeStep?:number, maxSubSteps?:number):boolean;
+
+
+ // Eventable mixins
+ addEventListener( event_name: string, callback: (event: any) => void ): void;
+ removeEventListener( event_name: string, callback: (event: any) => void): void;
+ dispatchEvent( event_name: string ): void;
+
+ // (extends from Object3D)
+ dispatchEvent( event: { type: string; target: any; } ): void;
+ }
+
+ export class Mesh extends THREE.Mesh {
+ constructor(geometry:THREE.Geometry, material?:THREE.Material, mass?:number);
+
+ applyCentralImpulse(force:THREE.Vector3):void;
+ applyImpulse(force:THREE.Vector3, offset:THREE.Vector3):void;
+ applyCentralForce(force:THREE.Vector3):void;
+ applyForce(force:THREE.Vector3, offset:THREE.Vector3):void;
+ getAngularVelocity():THREE.Vector3;
+ setAngularVelocity(velocity:THREE.Vector3):void;
+ getLinearVelocity():THREE.Vector3;
+ setLinearVelocity(velocity:THREE.Vector3):void;
+ setAngularFactor(factor:THREE.Vector3):void;
+ setLinearFactor(factor:THREE.Vector3):void;
+ setDamping(linear:number, angular:number):void;
+ setCcdMotionThreshold(threshold:number):void;
+ setCcdSweptSphereRadius(radius:number):void;
+
+
+ // Eventable mixins
+ addEventListener( event_name: string, callback: (event: any) => void ): void;
+ removeEventListener( event_name: string, callback: (event: any) => void): void;
+ dispatchEvent( event_name: string ): void;
+
+ // (extends from Object3D)
+ dispatchEvent( event: { type: string; target: any; } ): void;
+ }
+
+ export class PlaneMesh extends Mesh {
+ constructor(geometry:THREE.Geometry, material:THREE.Material, mass?:number);
+
+ }
+
+ export class HeightfieldMesh extends Mesh {
+ constructor(geometry:THREE.Geometry, material:THREE.Material, mass?:number, xdiv?:number, ydiv?:number);
+ }
+
+ export class BoxMesh extends Mesh {
+ constructor(geometry:THREE.Geometry, material:THREE.Material, mass?:number);
+ }
+
+ export class SphereMesh extends Mesh {
+ constructor(geometry:THREE.Geometry, material:THREE.Material, mass?:number);
+ }
+
+ export class CylinderMesh extends Mesh {
+ constructor(geometry:THREE.Geometry, material:THREE.Material, mass?:number);
+ }
+
+ export class CapsuleMesh extends Mesh {
+ constructor(geometry:THREE.Geometry, material:THREE.Material, mass?:number);
+ }
+
+ export class ConeMesh extends Mesh {
+ constructor(geometry:THREE.Geometry, material:THREE.Material, mass?:number);
+ }
+
+ export class ConcaveMesh extends Mesh {
+ constructor(geometry:THREE.Geometry, material:THREE.Material, mass?:number);
+ }
+
+ export class ConvexMesh extends Mesh {
+ constructor(geometry:THREE.Geometry, material:THREE.Material, mass?:number);
+ }
+
+ export class Vehicle {
+ constructor(mesh:Mesh, tuning?:VehicleTuning);
+
+ mesh:THREE.Mesh;
+ wheels:THREE.Mesh[];
+
+ addWheel(wheel_geometry:THREE.Geometry, wheel_material:THREE.Material, connection_point:THREE.Vector3, wheel_direction:THREE.Vector3, wheel_axle:THREE.Vector3, suspension_rest_length:number, wheel_radius:number, is_front_wheel:boolean, tuning?:VehicleTuning): void;
+ setSteering(amount: number, wheel?: THREE.Mesh): void;
+ setBrake(amount: number, wheel?: THREE.Mesh): void;
+ applyEngineForce(amount: number, wheel?: THREE.Mesh): void;
+ }
+
+ export class VehicleTuning {
+ constructor(suspension_stiffness?:number, suspension_compression?:number, suspension_damping?:number, max_suspension_travel?:number, friction_slip?:number, max_suspension_force?:number);
+
+ suspension_stiffness:number;
+ suspension_compression:number;
+ suspension_damping:number;
+ max_suspension_travel:number;
+ friction_slip:number;
+ max_suspension_force:number;
+ }
+}
+
diff --git a/physijs/tests/body.ts b/physijs/tests/body.ts
new file mode 100644
index 000000000..acf9df500
--- /dev/null
+++ b/physijs/tests/body.ts
@@ -0,0 +1,160 @@
+///
+///
+
+
+Physijs.scripts.worker = '../physijs_worker.js';
+Physijs.scripts.ammo = 'examples/js/ammo.js';
+
+var initScene, render, applyForce, setMousePosition, mouse_position,
+ ground_material, box_material,
+ projector, renderer, render_stats, physics_stats, scene, ground, light, camera, box, boxes = [];
+
+initScene = function() {
+ projector = new THREE.Projector;
+
+ renderer = new THREE.WebGLRenderer({ antialias: true });
+ renderer.setSize( window.innerWidth, window.innerHeight );
+ renderer.shadowMapEnabled = true;
+ renderer.shadowMapSoft = true;
+ document.getElementById( 'viewport' ).appendChild( renderer.domElement );
+
+ render_stats = new Stats();
+ render_stats.domElement.style.position = 'absolute';
+ render_stats.domElement.style.top = '1px';
+ render_stats.domElement.style.zIndex = 100;
+ document.getElementById( 'viewport' ).appendChild( render_stats.domElement );
+
+ physics_stats = new Stats();
+ physics_stats.domElement.style.position = 'absolute';
+ physics_stats.domElement.style.top = '50px';
+ physics_stats.domElement.style.zIndex = 100;
+ document.getElementById( 'viewport' ).appendChild( physics_stats.domElement );
+
+ scene = new Physijs.Scene();
+ scene.setGravity(new THREE.Vector3( 0, -30, 0 ));
+ scene.addEventListener(
+ 'update',
+ function() {
+ applyForce();
+ scene.simulate( undefined, 1 );
+ physics_stats.update();
+ }
+ );
+
+ camera = new THREE.PerspectiveCamera(
+ 35,
+ window.innerWidth / window.innerHeight,
+ 1,
+ 1000
+ );
+ camera.position.set( 60, 50, 60 );
+ camera.lookAt( scene.position );
+ scene.add( camera );
+
+ // Light
+ light = new THREE.DirectionalLight( 0xFFFFFF );
+ light.position.set( 20, 40, -15 );
+ light.target.position.copy( scene.position );
+ light.castShadow = true;
+ light.shadowCameraLeft = -60;
+ light.shadowCameraTop = -60;
+ light.shadowCameraRight = 60;
+ light.shadowCameraBottom = 60;
+ light.shadowCameraNear = 20;
+ light.shadowCameraFar = 200;
+ light.shadowBias = -.0001
+ light.shadowMapWidth = light.shadowMapHeight = 2048;
+ light.shadowDarkness = .7;
+ scene.add( light );
+
+ // Materials
+ ground_material = Physijs.createMaterial(
+ new THREE.MeshLambertMaterial({ map: THREE.ImageUtils.loadTexture( 'images/rocks.jpg' ) }),
+ .8, // high friction
+ .4 // low restitution
+ );
+ ground_material.map.wrapS = ground_material.map.wrapT = THREE.RepeatWrapping;
+ ground_material.map.repeat.set( 3, 3 );
+
+ box_material = Physijs.createMaterial(
+ new THREE.MeshLambertMaterial({ map: THREE.ImageUtils.loadTexture( 'images/plywood.jpg' ) }),
+ .4, // low friction
+ .6 // high restitution
+ );
+ box_material.map.wrapS = ground_material.map.wrapT = THREE.RepeatWrapping;
+ box_material.map.repeat.set( .25, .25 );
+
+ // Ground
+ ground = new Physijs.BoxMesh(
+ new THREE.BoxGeometry(100, 1, 100),
+ ground_material,
+ 0 // mass
+ );
+ ground.receiveShadow = true;
+ scene.add( ground );
+
+ for ( var i = 0; i < 10; i++ ) {
+ box = new Physijs.BoxMesh(
+ new THREE.BoxGeometry( 4, 4, 4 ),
+ box_material
+ );
+ box.position.set(
+ Math.random() * 50 - 25,
+ 10 + Math.random() * 5,
+ Math.random() * 50 - 25
+ );
+ box.rotation.set(
+ Math.random() * Math.PI * 2,
+ Math.random() * Math.PI * 2,
+ Math.random() * Math.PI * 2
+ );
+ box.scale.set(
+ Math.random() * 1 + .5,
+ Math.random() * 1 + .5,
+ Math.random() * 1 + .5
+ );
+ box.castShadow = true;
+ scene.add( box );
+ boxes.push( box );
+ }
+
+ renderer.domElement.addEventListener( 'mousemove', setMousePosition );
+
+ requestAnimationFrame( render );
+ scene.simulate();
+};
+
+render = function() {
+ requestAnimationFrame( render );
+ renderer.render( scene, camera );
+ render_stats.update();
+};
+
+setMousePosition = function( evt ) {
+ // Find where mouse cursor intersects the ground plane
+ var vector = new THREE.Vector3(
+ ( evt.clientX / renderer.domElement.clientWidth ) * 2 - 1,
+ -( ( evt.clientY / renderer.domElement.clientHeight ) * 2 - 1 ),
+ .5
+ );
+ projector.unprojectVector( vector, camera );
+ vector.sub( camera.position ).normalize();
+
+ var coefficient = (box.position.y - camera.position.y) / vector.y
+ mouse_position = camera.position.clone().add( vector.multiplyScalar( coefficient ) );
+};
+
+applyForce = function() {
+ if (!mouse_position) return;
+ var strength = 35, distance, effect, offset, box;
+
+ for ( var i = 0; i < boxes.length; i++ ) {
+ box = boxes[i];
+ distance = mouse_position.distanceTo( box.position ),
+ effect = mouse_position.clone().sub( box.position ).normalize().multiplyScalar( strength / distance ).negate(),
+ offset = mouse_position.clone().sub( box.position );
+ box.applyImpulse( effect, offset );
+ }
+};
+
+window.onload = initScene;
diff --git a/physijs/tests/collisions.ts b/physijs/tests/collisions.ts
new file mode 100644
index 000000000..bc43a60d6
--- /dev/null
+++ b/physijs/tests/collisions.ts
@@ -0,0 +1,171 @@
+///
+///
+
+
+Physijs.scripts.worker = '../physijs_worker.js';
+Physijs.scripts.ammo = 'examples/js/ammo.js';
+
+var initScene, render, _boxes = [], spawnBox,
+ renderer, render_stats, physics_stats, scene, ground_material, ground, light, camera;
+
+initScene = function() {
+ renderer = new THREE.WebGLRenderer({ antialias: true });
+ renderer.setSize( window.innerWidth, window.innerHeight );
+ renderer.shadowMapEnabled = true;
+ renderer.shadowMapSoft = true;
+ document.getElementById( 'viewport' ).appendChild( renderer.domElement );
+
+ render_stats = new Stats();
+ render_stats.domElement.style.position = 'absolute';
+ render_stats.domElement.style.top = '0px';
+ render_stats.domElement.style.zIndex = 100;
+ document.getElementById( 'viewport' ).appendChild( render_stats.domElement );
+
+ physics_stats = new Stats();
+ physics_stats.domElement.style.position = 'absolute';
+ physics_stats.domElement.style.top = '50px';
+ physics_stats.domElement.style.zIndex = 100;
+ document.getElementById( 'viewport' ).appendChild( physics_stats.domElement );
+
+ scene = new Physijs.Scene;
+ scene.setGravity(new THREE.Vector3( 0, -30, 0 ));
+ scene.addEventListener(
+ 'update',
+ function() {
+ scene.simulate( undefined, 1 );
+ physics_stats.update();
+ }
+ );
+
+ camera = new THREE.PerspectiveCamera(
+ 35,
+ window.innerWidth / window.innerHeight,
+ 1,
+ 1000
+ );
+ camera.position.set( 60, 50, 60 );
+ camera.lookAt( scene.position );
+ scene.add( camera );
+
+ // Light
+ light = new THREE.DirectionalLight( 0xFFFFFF );
+ light.position.set( 20, 40, -15 );
+ light.target.position.copy( scene.position );
+ light.castShadow = true;
+ light.shadowCameraLeft = -60;
+ light.shadowCameraTop = -60;
+ light.shadowCameraRight = 60;
+ light.shadowCameraBottom = 60;
+ light.shadowCameraNear = 20;
+ light.shadowCameraFar = 200;
+ light.shadowBias = -.0001
+ light.shadowMapWidth = light.shadowMapHeight = 2048;
+ light.shadowDarkness = .7;
+ scene.add( light );
+
+ // Ground
+ ground_material = Physijs.createMaterial(
+ new THREE.MeshLambertMaterial({ map: THREE.ImageUtils.loadTexture( 'images/rocks.jpg' ) }),
+ .8, // high friction
+ .3 // low restitution
+ );
+ ground_material.map.wrapS = ground_material.map.wrapT = THREE.RepeatWrapping;
+ ground_material.map.repeat.set( 3, 3 );
+
+ ground = new Physijs.BoxMesh(
+ new THREE.BoxGeometry(100, 1, 100),
+ ground_material,
+ 0 // mass
+ );
+ ground.receiveShadow = true;
+ scene.add( ground );
+
+ spawnBox();
+
+ requestAnimationFrame( render );
+ scene.simulate();
+};
+
+spawnBox = (function() {
+
+ var box_geometry = new THREE.BoxGeometry( 4, 4, 4 ),
+ handleCollision = function( collided_with, linearVelocity, angularVelocity ) {
+ var target = this;
+ target.collisions = 0;
+ switch (++target.collisions) {
+
+ case 1:
+ target.material.color.setHex(0xcc8855);
+ break;
+
+ case 2:
+ target.material.color.setHex(0xbb9955);
+ break;
+
+ case 3:
+ target.material.color.setHex(0xaaaa55);
+ break;
+
+ case 4:
+ target.material.color.setHex(0x99bb55);
+ break;
+
+ case 5:
+ target.material.color.setHex(0x88cc55);
+ break;
+
+ case 6:
+ target.material.color.setHex(0x77dd55);
+ break;
+ }
+ },
+ createBox = function() {
+ var box, material;
+
+ material = Physijs.createMaterial(
+ new THREE.MeshLambertMaterial({ map: THREE.ImageUtils.loadTexture( 'images/plywood.jpg' ) }),
+ .6, // medium friction
+ .3 // low restitution
+ );
+ material.map.wrapS = material.map.wrapT = THREE.RepeatWrapping;
+ material.map.repeat.set( .5, .5 );
+
+ //material = new THREE.MeshLambertMaterial({ map: THREE.ImageUtils.loadTexture( 'images/rocks.jpg' ) });
+
+ box = new Physijs.BoxMesh(
+ box_geometry,
+ material
+ );
+
+ box.collisions = 0;
+
+ box.position.set(
+ Math.random() * 15 - 7.5,
+ 25,
+ Math.random() * 15 - 7.5
+ );
+
+ box.rotation.set(
+ Math.random() * Math.PI,
+ Math.random() * Math.PI,
+ Math.random() * Math.PI
+ );
+
+ box.castShadow = true;
+ box.addEventListener( 'collision', handleCollision );
+ box.addEventListener( 'ready', spawnBox );
+ scene.add( box );
+ };
+
+ return function() {
+ setTimeout( createBox, 1000 );
+ };
+})();
+
+render = function() {
+ requestAnimationFrame( render );
+ renderer.render( scene, camera );
+ render_stats.update();
+};
+
+window.onload = initScene;
\ No newline at end of file
diff --git a/physijs/tests/compound.ts b/physijs/tests/compound.ts
new file mode 100644
index 000000000..bfd103ca7
--- /dev/null
+++ b/physijs/tests/compound.ts
@@ -0,0 +1,238 @@
+///
+///
+
+
+Physijs.scripts.worker = '../physijs_worker.js';
+Physijs.scripts.ammo = 'examples/js/ammo.js';
+
+var initScene, render, renderer, render_stats, physics_stats, scene, ground, light, camera, spawnChair,
+ ground_material, chair_material;
+
+initScene = function() {
+ renderer = new THREE.WebGLRenderer({ antialias: true });
+ renderer.setSize( window.innerWidth, window.innerHeight );
+ renderer.shadowMapEnabled = true;
+ renderer.shadowMapSoft = true;
+ document.getElementById( 'viewport' ).appendChild( renderer.domElement );
+
+ render_stats = new Stats();
+ render_stats.domElement.style.position = 'absolute';
+ render_stats.domElement.style.top = '0px';
+ render_stats.domElement.style.zIndex = 100;
+ document.getElementById( 'viewport' ).appendChild( render_stats.domElement );
+
+ physics_stats = new Stats();
+ physics_stats.domElement.style.position = 'absolute';
+ physics_stats.domElement.style.top = '50px';
+ physics_stats.domElement.style.zIndex = 100;
+ document.getElementById( 'viewport' ).appendChild( physics_stats.domElement );
+
+ scene = new Physijs.Scene;
+ scene.setGravity(new THREE.Vector3( 0, -50, 0 ));
+ scene.addEventListener(
+ 'update',
+ function() {
+ scene.simulate( undefined, 2 );
+ physics_stats.update();
+ }
+ );
+
+ camera = new THREE.PerspectiveCamera(
+ 35,
+ window.innerWidth / window.innerHeight,
+ 1,
+ 1000
+ );
+ camera.position.set( 60, 50, 60 );
+ camera.lookAt( scene.position );
+ scene.add( camera );
+
+ // Light
+ light = new THREE.DirectionalLight( 0xFFFFFF );
+ light.position.set( 20, 40, -15 );
+ light.target.position.copy( scene.position );
+ light.castShadow = true;
+ light.shadowCameraLeft = -60;
+ light.shadowCameraTop = -60;
+ light.shadowCameraRight = 60;
+ light.shadowCameraBottom = 60;
+ light.shadowCameraNear = 20;
+ light.shadowCameraFar = 200;
+ light.shadowBias = -.0001
+ light.shadowMapWidth = light.shadowMapHeight = 2048;
+ light.shadowDarkness = .7;
+ scene.add( light );
+
+ // Materials
+ ground_material = Physijs.createMaterial(
+ new THREE.MeshLambertMaterial({ map: THREE.ImageUtils.loadTexture( 'images/rocks.jpg' ) }),
+ .8, // high friction
+ .4 // low restitution
+ );
+ ground_material.map.wrapS = ground_material.map.wrapT = THREE.RepeatWrapping;
+ ground_material.map.repeat.set( 3, 3 );
+
+ chair_material = Physijs.createMaterial(
+ new THREE.MeshLambertMaterial({ map: THREE.ImageUtils.loadTexture( 'images/wood.jpg' ) }),
+ .6, // medium friction
+ .2 // low restitution
+ );
+ chair_material.map.wrapS = chair_material.map.wrapT = THREE.RepeatWrapping;
+ chair_material.map.repeat.set( .25, .25 );
+
+ // Ground
+ ground = new Physijs.BoxMesh(
+ new THREE.BoxGeometry(100, 1, 100),
+ ground_material,
+ 0 // mass
+ );;
+ ground.receiveShadow = true;
+ scene.add( ground );
+
+ spawnChair();
+
+ requestAnimationFrame( render );
+ scene.simulate();
+};
+
+spawnChair = (function() {
+ var buildBack, buildLegs, doSpawn;
+
+ buildBack = function() {
+ var back, _object;
+
+ back = new Physijs.BoxMesh(
+ new THREE.BoxGeometry( 5, 1, .5 ),
+ chair_material
+ );
+ back.position.y = 5;
+ back.position.z = -2.5;
+ back.castShadow = true;
+ back.receiveShadow = true;
+
+ // rungs - relative to back
+ _object = new Physijs.BoxMesh(
+ new THREE.BoxGeometry( 1, 5, .5 ),
+ chair_material
+ );
+ _object.position.y = -3;
+ _object.position.x = -2;
+ _object.castShadow = true;
+ _object.receiveShadow = true;
+ back.add( _object );
+
+ _object = new Physijs.BoxMesh(
+ new THREE.BoxGeometry( 1, 5, .5 ),
+ chair_material
+ );
+ _object.position.y = -3;
+ _object.castShadow = true;
+ _object.receiveShadow = true;
+ back.add( _object );
+
+ _object = new Physijs.BoxMesh(
+ new THREE.BoxGeometry( 1, 5, .5 ),
+ chair_material
+ );
+ _object.position.y = -3;
+ _object.position.x = 2;
+ _object.castShadow = true;
+ _object.receiveShadow = true;
+ back.add( _object );
+
+ return back;
+ };
+
+ buildLegs = function() {
+ var leg, _leg;
+
+ // back left
+ leg = new Physijs.BoxMesh(
+ new THREE.BoxGeometry( .5, 4, .5 ),
+ chair_material
+ );
+ leg.position.x = 2.25;
+ leg.position.z = -2.25;
+ leg.position.y = -2.5;
+ leg.castShadow = true;
+ leg.receiveShadow = true;
+
+ // back right - relative to back left leg
+ _leg = new Physijs.BoxMesh(
+ new THREE.BoxGeometry( .5, 4, .5 ),
+ chair_material
+ );
+ _leg.position.x = -4.5;
+ _leg.castShadow = true;
+ _leg.receiveShadow = true;
+ leg.add( _leg );
+
+ // front left - relative to back left leg
+ _leg = new Physijs.BoxMesh(
+ new THREE.BoxGeometry( .5, 4, .5 ),
+ chair_material
+ );
+ _leg.position.z = 4.5;
+ _leg.castShadow = true;
+ _leg.receiveShadow = true;
+ leg.add( _leg );
+
+ // front right - relative to back left leg
+ _leg = new Physijs.BoxMesh(
+ new THREE.BoxGeometry( .5, 4, .5 ),
+ chair_material
+ );
+ _leg.position.x = -4.5;
+ _leg.position.z = 4.5;
+ _leg.castShadow = true;
+ _leg.receiveShadow = true;
+ leg.add( _leg );
+
+ return leg;
+ };
+
+ doSpawn = function() {
+ var chair, back, legs;
+
+ // seat of the chair
+ chair = new Physijs.BoxMesh(
+ new THREE.BoxGeometry( 5, 1, 5 ),
+ chair_material
+ );
+ chair.castShadow = true;
+ chair.receiveShadow = true;
+
+ // back - relative to chair ( seat )
+ back = buildBack();
+ chair.add( back );
+
+ // legs - relative to chair ( seat )
+ legs = buildLegs();
+ chair.add( legs );
+
+ chair.position.y = 20;
+ chair.position.x = Math.random() * 50 - 25;
+ chair.position.z = Math.random() * 50 - 25;
+
+ chair.rotation.set(
+ Math.random() * Math.PI * 2,
+ Math.random() * Math.PI * 2,
+ Math.random() * Math.PI * 2
+ );
+
+ chair.addEventListener( 'ready', spawnChair );
+ scene.add( chair );
+ };
+
+ return function() {
+ setTimeout( doSpawn, 500 );
+ };
+})();
+
+render = function() {
+ requestAnimationFrame( render );
+ renderer.render( scene, camera );
+ render_stats.update();
+};
+
+window.onload = initScene;
diff --git a/physijs/tests/constraints_car.ts b/physijs/tests/constraints_car.ts
new file mode 100644
index 000000000..b74c44449
--- /dev/null
+++ b/physijs/tests/constraints_car.ts
@@ -0,0 +1,257 @@
+///
+///
+
+
+Physijs.scripts.worker = '../physijs_worker.js';
+Physijs.scripts.ammo = 'examples/js/ammo.js';
+
+var initScene, render,
+ ground_material, car_material, wheel_material, wheel_geometry,
+ projector, renderer, render_stats, physics_stats, scene, ground_geometry, ground, light, camera,
+ car: any = {};
+
+initScene = function() {
+ projector = new THREE.Projector;
+
+ renderer = new THREE.WebGLRenderer({ antialias: true });
+ renderer.setSize( window.innerWidth, window.innerHeight );
+ renderer.shadowMapEnabled = true;
+ renderer.shadowMapSoft = true;
+ document.getElementById( 'viewport' ).appendChild( renderer.domElement );
+
+ render_stats = new Stats();
+ render_stats.domElement.style.position = 'absolute';
+ render_stats.domElement.style.top = '0px';
+ render_stats.domElement.style.zIndex = 100;
+ document.getElementById( 'viewport' ).appendChild( render_stats.domElement );
+
+ physics_stats = new Stats();
+ physics_stats.domElement.style.position = 'absolute';
+ physics_stats.domElement.style.top = '50px';
+ physics_stats.domElement.style.zIndex = 100;
+ document.getElementById( 'viewport' ).appendChild( physics_stats.domElement );
+
+ scene = new Physijs.Scene;
+ scene.setGravity(new THREE.Vector3( 0, -30, 0 ));
+ scene.addEventListener(
+ 'update',
+ function() {
+ scene.simulate( undefined, 2 );
+ physics_stats.update();
+ }
+ );
+
+ camera = new THREE.PerspectiveCamera(
+ 35,
+ window.innerWidth / window.innerHeight,
+ 1,
+ 1000
+ );
+ camera.position.set( 60, 50, 60 );
+ camera.lookAt( scene.position );
+ scene.add( camera );
+
+ // Light
+ light = new THREE.DirectionalLight( 0xFFFFFF );
+ light.position.set( 20, 40, -15 );
+ light.target.position.copy( scene.position );
+ light.castShadow = true;
+ light.shadowCameraLeft = -60;
+ light.shadowCameraTop = -60;
+ light.shadowCameraRight = 60;
+ light.shadowCameraBottom = 60;
+ light.shadowCameraNear = 20;
+ light.shadowCameraFar = 200;
+ light.shadowBias = -.0001
+ light.shadowMapWidth = light.shadowMapHeight = 2048;
+ light.shadowDarkness = .7;
+ scene.add( light );
+
+ // Materials
+ ground_material = Physijs.createMaterial(
+ new THREE.MeshLambertMaterial({ map: THREE.ImageUtils.loadTexture( 'images/rocks.jpg' ) }),
+ .8, // high friction
+ .4 // low restitution
+ );
+ ground_material.map.wrapS = ground_material.map.wrapT = THREE.RepeatWrapping;
+ ground_material.map.repeat.set( 3, 3 );
+
+ // Ground
+ ground = new Physijs.BoxMesh(
+ new THREE.BoxGeometry(100, 1, 100),
+ ground_material,
+ 0 // mass
+ );
+ ground.receiveShadow = true;
+ scene.add( ground );
+
+
+ // Car
+ car_material = Physijs.createMaterial(
+ new THREE.MeshLambertMaterial({ color: 0xff6666 }),
+ .8, // high friction
+ .2 // low restitution
+ );
+
+ wheel_material = Physijs.createMaterial(
+ new THREE.MeshLambertMaterial({ color: 0x444444 }),
+ .8, // high friction
+ .5 // medium restitution
+ );
+ wheel_geometry = new THREE.CylinderGeometry( 2, 2, 1, 8 );
+
+ car.body = new Physijs.BoxMesh(
+ new THREE.BoxGeometry( 10, 5, 7 ),
+ car_material,
+ 1000
+ );
+ car.body.position.y = 10;
+ car.body.receiveShadow = car.body.castShadow = true;
+ scene.add( car.body );
+
+ car.wheel_fl = new Physijs.CylinderMesh(
+ wheel_geometry,
+ wheel_material,
+ 500
+ );
+ car.wheel_fl.rotation.x = Math.PI / 2;
+ car.wheel_fl.position.set( -3.5, 6.5, 5 );
+ car.wheel_fl.receiveShadow = car.wheel_fl.castShadow = true;
+ scene.add( car.wheel_fl );
+ car.wheel_fl_constraint = new Physijs.DOFConstraint(
+ car.wheel_fl, car.body, new THREE.Vector3( -3.5, 6.5, 5 )
+ );
+ scene.addConstraint( car.wheel_fl_constraint );
+ car.wheel_fl_constraint.setAngularLowerLimit({ x: 0, y: -Math.PI / 8, z: 1 });
+ car.wheel_fl_constraint.setAngularUpperLimit({ x: 0, y: Math.PI / 8, z: 0 });
+
+ car.wheel_fr = new Physijs.CylinderMesh(
+ wheel_geometry,
+ wheel_material,
+ 500
+ );
+ car.wheel_fr.rotation.x = Math.PI / 2;
+ car.wheel_fr.position.set( -3.5, 6.5, -5 );
+ car.wheel_fr.receiveShadow = car.wheel_fr.castShadow = true;
+ scene.add( car.wheel_fr );
+ car.wheel_fr_constraint = new Physijs.DOFConstraint(
+ car.wheel_fr, car.body, new THREE.Vector3( -3.5, 6.5, -5 )
+ );
+ scene.addConstraint( car.wheel_fr_constraint );
+ car.wheel_fr_constraint.setAngularLowerLimit({ x: 0, y: -Math.PI / 8, z: 1 });
+ car.wheel_fr_constraint.setAngularUpperLimit({ x: 0, y: Math.PI / 8, z: 0 });
+
+ car.wheel_bl = new Physijs.CylinderMesh(
+ wheel_geometry,
+ wheel_material,
+ 500
+ );
+ car.wheel_bl.rotation.x = Math.PI / 2;
+ car.wheel_bl.position.set( 3.5, 6.5, 5 );
+ car.wheel_bl.receiveShadow = car.wheel_bl.castShadow = true;
+ scene.add( car.wheel_bl );
+ car.wheel_bl_constraint = new Physijs.DOFConstraint(
+ car.wheel_bl, car.body, new THREE.Vector3( 3.5, 6.5, 5 )
+ );
+ scene.addConstraint( car.wheel_bl_constraint );
+ car.wheel_bl_constraint.setAngularLowerLimit({ x: 0, y: 0, z: 0 });
+ car.wheel_bl_constraint.setAngularUpperLimit({ x: 0, y: 0, z: 0 });
+
+ car.wheel_br = new Physijs.CylinderMesh(
+ wheel_geometry,
+ wheel_material,
+ 500
+ );
+ car.wheel_br.rotation.x = Math.PI / 2;
+ car.wheel_br.position.set( 3.5, 6.5, -5 );
+ car.wheel_br.receiveShadow = car.wheel_br.castShadow = true;
+ scene.add( car.wheel_br );
+ car.wheel_br_constraint = new Physijs.DOFConstraint(
+ car.wheel_br, car.body, new THREE.Vector3( 3.5, 6.5, -5 )
+ );
+ scene.addConstraint( car.wheel_br_constraint );
+ car.wheel_br_constraint.setAngularLowerLimit({ x: 0, y: 0, z: 0 });
+ car.wheel_br_constraint.setAngularUpperLimit({ x: 0, y: 0, z: 0 });
+
+ document.addEventListener(
+ 'keydown',
+ function( ev ) {
+ switch( ev.keyCode ) {
+ case 37:
+ // Left
+ car.wheel_fl_constraint.configureAngularMotor( 1, -Math.PI / 2, Math.PI / 2, 1, 200 );
+ car.wheel_fr_constraint.configureAngularMotor( 1, -Math.PI / 2, Math.PI / 2, 1, 200 );
+ car.wheel_fl_constraint.enableAngularMotor( 1 );
+ car.wheel_fr_constraint.enableAngularMotor( 1 );
+ break;
+
+ case 39:
+ // Right
+ car.wheel_fl_constraint.configureAngularMotor( 1, -Math.PI / 2, Math.PI / 2, -1, 200 );
+ car.wheel_fr_constraint.configureAngularMotor( 1, -Math.PI / 2, Math.PI / 2, -1, 200 );
+ car.wheel_fl_constraint.enableAngularMotor( 1 );
+ car.wheel_fr_constraint.enableAngularMotor( 1 );
+ break;
+
+ case 38:
+ // Up
+ car.wheel_bl_constraint.configureAngularMotor( 2, 1, 0, 5, 2000 );
+ car.wheel_br_constraint.configureAngularMotor( 2, 1, 0, 5, 2000 );
+ car.wheel_bl_constraint.enableAngularMotor( 2 );
+ car.wheel_br_constraint.enableAngularMotor( 2 );
+ break;
+
+ case 40:
+ // Down
+ car.wheel_bl_constraint.configureAngularMotor( 2, 1, 0, -5, 2000 );
+ car.wheel_br_constraint.configureAngularMotor( 2, 1, 0, -5, 2000 );
+ car.wheel_bl_constraint.enableAngularMotor( 2 );
+ //car.wheel_br_constraint.enableAngularMotor( 2 );
+ break;
+ }
+ }
+ );
+
+ document.addEventListener(
+ 'keyup',
+ function( ev ) {
+ switch( ev.keyCode ) {
+ case 37:
+ // Left
+ car.wheel_fl_constraint.disableAngularMotor( 1 );
+ car.wheel_fr_constraint.disableAngularMotor( 1 );
+ break;
+
+ case 39:
+ // Right
+ car.wheel_fl_constraint.disableAngularMotor( 1 );
+ car.wheel_fr_constraint.disableAngularMotor( 1 );
+ break;
+
+ case 38:
+ // Up
+ car.wheel_bl_constraint.disableAngularMotor( 2 );
+ car.wheel_br_constraint.disableAngularMotor( 2 );
+ break;
+
+ case 40:
+ // Down
+ car.wheel_bl_constraint.disableAngularMotor( 2 );
+ car.wheel_br_constraint.disableAngularMotor( 2 );
+ break;
+ }
+ }
+ );
+
+
+ requestAnimationFrame( render );
+ scene.simulate();
+};
+
+render = function() {
+ requestAnimationFrame( render );
+ renderer.render( scene, camera );
+ render_stats.update();
+};
+
+window.onload = initScene;
diff --git a/physijs/tests/heightfield.ts b/physijs/tests/heightfield.ts
new file mode 100644
index 000000000..19d0e8c78
--- /dev/null
+++ b/physijs/tests/heightfield.ts
@@ -0,0 +1,189 @@
+///
+///
+
+var TWEEN: any;
+var SimplexNoise: any;
+
+
+Physijs.scripts.worker = '../physijs_worker.js';
+Physijs.scripts.ammo = 'examples/js/ammo.js';
+
+var initScene, render, createShape, NoiseGen,
+ renderer, render_stats, physics_stats, scene, light, ground, ground_geometry, ground_material, camera;
+
+initScene = function() {
+ TWEEN.start();
+
+ renderer = new THREE.WebGLRenderer({ antialias: true });
+ renderer.setSize( window.innerWidth, window.innerHeight );
+ renderer.shadowMapEnabled = true;
+ renderer.shadowMapSoft = true;
+ document.getElementById( 'viewport' ).appendChild( renderer.domElement );
+
+ render_stats = new Stats();
+ render_stats.domElement.style.position = 'absolute';
+ render_stats.domElement.style.top = '0px';
+ render_stats.domElement.style.zIndex = 100;
+ document.getElementById( 'viewport' ).appendChild( render_stats.domElement );
+
+ physics_stats = new Stats();
+ physics_stats.domElement.style.position = 'absolute';
+ physics_stats.domElement.style.top = '50px';
+ physics_stats.domElement.style.zIndex = 100;
+ document.getElementById( 'viewport' ).appendChild( physics_stats.domElement );
+
+ scene = new Physijs.Scene({ fixedTimeStep: 1 / 120 });
+ scene.setGravity(new THREE.Vector3( 0, -30, 0 ));
+ scene.addEventListener(
+ 'update',
+ function() {
+ scene.simulate( undefined, 2 );
+ physics_stats.update();
+ }
+ );
+
+ camera = new THREE.PerspectiveCamera(
+ 35,
+ window.innerWidth / window.innerHeight,
+ 1,
+ 1000
+ );
+ camera.position.set( 60, 50, 60 );
+ camera.lookAt( scene.position );
+ scene.add( camera );
+
+ // Light
+ light = new THREE.DirectionalLight( 0xFFFFFF );
+ light.position.set( 20, 40, -15 );
+ light.target.position.copy( scene.position );
+ light.castShadow = true;
+ light.shadowCameraLeft = -60;
+ light.shadowCameraTop = -60;
+ light.shadowCameraRight = 60;
+ light.shadowCameraBottom = 60;
+ light.shadowCameraNear = 20;
+ light.shadowCameraFar = 200;
+ light.shadowBias = -.0001
+ light.shadowMapWidth = light.shadowMapHeight = 2048;
+ light.shadowDarkness = .7;
+ scene.add( light );
+
+ // Materials
+ ground_material = Physijs.createMaterial(
+ new THREE.MeshLambertMaterial({ map: THREE.ImageUtils.loadTexture( 'images/grass.png' ) }),
+ .8, // high friction
+ .4 // low restitution
+ );
+ ground_material.map.wrapS = ground_material.map.wrapT = THREE.RepeatWrapping;
+ ground_material.map.repeat.set( 2.5, 2.5 );
+
+ // Ground
+ NoiseGen = new SimplexNoise;
+
+ ground_geometry = new THREE.PlaneGeometry( 75, 75, 50, 50 );
+ for ( var i = 0; i < ground_geometry.vertices.length; i++ ) {
+ var vertex = ground_geometry.vertices[i];
+ vertex.z = NoiseGen.noise( vertex.x / 10, vertex.y / 10 ) * 2;
+ }
+ ground_geometry.computeFaceNormals();
+ ground_geometry.computeVertexNormals();
+
+ // If your plane is not square as far as face count then the HeightfieldMesh
+ // takes two more arguments at the end: # of x faces and # of y faces that were passed to THREE.PlaneMaterial
+ ground = new Physijs.HeightfieldMesh(
+ ground_geometry,
+ ground_material,
+ 0, // mass
+ 50,
+ 50
+ );
+ ground.rotation.x = Math.PI / -2;
+ ground.receiveShadow = true;
+ scene.add( ground );
+
+ requestAnimationFrame( render );
+ scene.simulate();
+
+ createShape();
+};
+
+render = function() {
+ requestAnimationFrame( render );
+ renderer.render( scene, camera );
+ render_stats.update();
+};
+
+createShape = (function() {
+ var addshapes = true,
+ shapes = 0,
+ box_geometry = new THREE.BoxGeometry( 3, 3, 3 ),
+ sphere_geometry = new THREE.SphereGeometry( 1.5, 32, 32 ),
+ cylinder_geometry = new THREE.CylinderGeometry( 2, 2, 1, 32 ),
+ cone_geometry = new THREE.CylinderGeometry( 0, 2, 4, 32 ),
+ octahedron_geometry = new THREE.OctahedronGeometry( 1.7, 1 ),
+ torus_geometry = new THREE.TorusKnotGeometry ( 1.7, .2, 32, 4 ),
+ doCreateShape;
+
+ setTimeout(
+ function addListener() {
+ var button = document.getElementById( 'stop' );
+ if ( button ) {
+ button.addEventListener( 'click', function() { addshapes = false; } );
+ } else {
+ setTimeout( addListener );
+ }
+ }
+ );
+
+ doCreateShape = function() {
+ var shape, material = new THREE.MeshLambertMaterial({ opacity: 0, transparent: true });
+
+ switch ( Math.floor(Math.random() * 2) ) {
+ case 0:
+ shape = new Physijs.BoxMesh(
+ box_geometry,
+ material
+ );
+ break;
+
+ case 1:
+ shape = new Physijs.SphereMesh(
+ sphere_geometry,
+ material,
+ undefined
+ );
+ break;
+ }
+
+ shape.material.color.setRGB( Math.random() * 100 / 100, Math.random() * 100 / 100, Math.random() * 100 / 100 );
+ shape.castShadow = true;
+ shape.receiveShadow = true;
+
+ shape.position.set(
+ Math.random() * 30 - 15,
+ 20,
+ Math.random() * 30 - 15
+ );
+
+ shape.rotation.set(
+ Math.random() * Math.PI,
+ Math.random() * Math.PI,
+ Math.random() * Math.PI
+ );
+
+ if ( addshapes ) {
+ shape.addEventListener( 'ready', createShape );
+ }
+ scene.add( shape );
+
+ new TWEEN.Tween(shape.material).to({opacity: 1}, 500).start();
+
+ document.getElementById('shapecount').textContent = (++shapes) + ' shapes created';
+ };
+
+ return function() {
+ setTimeout( doCreateShape, 250 );
+ };
+})();
+
+window.onload = initScene;
\ No newline at end of file
diff --git a/physijs/tests/jenga.ts b/physijs/tests/jenga.ts
new file mode 100644
index 000000000..05bbd7861
--- /dev/null
+++ b/physijs/tests/jenga.ts
@@ -0,0 +1,236 @@
+///
+///
+
+
+Physijs.scripts.worker = '../physijs_worker.js';
+Physijs.scripts.ammo = 'examples/js/ammo.js';
+
+var initScene, initEventHandling, render, createTower,
+ renderer, render_stats, physics_stats, scene, dir_light, am_light, camera,
+ table, blocks = [], table_material, block_material, intersect_plane, _i,
+ selected_block = null, mouse_pos = new THREE.Vector3(), block_offset = new THREE.Vector3(), _v3 = new THREE.Vector3();
+
+initScene = function() {
+ renderer = new THREE.WebGLRenderer({ antialias: true });
+ renderer.setSize( window.innerWidth, window.innerHeight );
+ renderer.shadowMapEnabled = true;
+ renderer.shadowMapSoft = true;
+ document.getElementById( 'viewport' ).appendChild( renderer.domElement );
+
+ render_stats = new Stats();
+ render_stats.domElement.style.position = 'absolute';
+ render_stats.domElement.style.top = '1px';
+ render_stats.domElement.style.zIndex = 100;
+ document.getElementById( 'viewport' ).appendChild( render_stats.domElement );
+
+ physics_stats = new Stats();
+ physics_stats.domElement.style.position = 'absolute';
+ physics_stats.domElement.style.top = '50px';
+ physics_stats.domElement.style.zIndex = 100;
+ document.getElementById( 'viewport' ).appendChild( physics_stats.domElement );
+
+ scene = new Physijs.Scene({ fixedTimeStep: 1 / 120 });
+ scene.setGravity(new THREE.Vector3( 0, -30, 0 ));
+ scene.addEventListener(
+ 'update',
+ function() {
+
+ if ( selected_block !== null ) {
+
+ _v3.copy( mouse_pos ).add( block_offset ).sub( selected_block.position ).multiplyScalar( 5 );
+ _v3.y = 0;
+ selected_block.setLinearVelocity( _v3 );
+
+ // Reactivate all of the blocks
+ _v3.set( 0, 0, 0 );
+ for ( _i = 0; _i < blocks.length; _i++ ) {
+ blocks[_i].applyCentralImpulse( _v3 );
+ }
+ }
+
+ scene.simulate( undefined, 1 );
+ physics_stats.update();
+ }
+ );
+
+ camera = new THREE.PerspectiveCamera(
+ 35,
+ window.innerWidth / window.innerHeight,
+ 1,
+ 1000
+ );
+ camera.position.set( 25, 20, 25 );
+ camera.lookAt(new THREE.Vector3( 0, 7, 0 ));
+ scene.add( camera );
+
+ // ambient light
+ am_light = new THREE.AmbientLight( 0x444444 );
+ scene.add( am_light );
+
+ // directional light
+ dir_light = new THREE.DirectionalLight( 0xFFFFFF );
+ dir_light.position.set( 20, 30, -5 );
+ dir_light.target.position.copy( scene.position );
+ dir_light.castShadow = true;
+ dir_light.shadowCameraLeft = -30;
+ dir_light.shadowCameraTop = -30;
+ dir_light.shadowCameraRight = 30;
+ dir_light.shadowCameraBottom = 30;
+ dir_light.shadowCameraNear = 20;
+ dir_light.shadowCameraFar = 200;
+ dir_light.shadowBias = -.001
+ dir_light.shadowMapWidth = dir_light.shadowMapHeight = 2048;
+ dir_light.shadowDarkness = .5;
+ scene.add( dir_light );
+
+ // Materials
+ table_material = Physijs.createMaterial(
+ new THREE.MeshLambertMaterial({ map: THREE.ImageUtils.loadTexture( 'images/wood.jpg' ), ambient: 0xFFFFFF }),
+ .9, // high friction
+ .2 // low restitution
+ );
+ table_material.map.wrapS = table_material.map.wrapT = THREE.RepeatWrapping;
+ table_material.map.repeat.set( 5, 5 );
+
+ block_material = Physijs.createMaterial(
+ new THREE.MeshLambertMaterial({ map: THREE.ImageUtils.loadTexture( 'images/plywood.jpg' ), ambient: 0xFFFFFF }),
+ .4, // medium friction
+ .4 // medium restitution
+ );
+ block_material.map.wrapS = block_material.map.wrapT = THREE.RepeatWrapping;
+ block_material.map.repeat.set( 1, .5 );
+
+ // Table
+ table = new Physijs.BoxMesh(
+ new THREE.BoxGeometry(50, 1, 50),
+ table_material,
+ 0
+ );
+ table.position.y = -.5;
+ table.receiveShadow = true;
+ scene.add( table );
+
+ createTower();
+
+ intersect_plane = new THREE.Mesh(
+ new THREE.PlaneGeometry( 150, 150 ),
+ new THREE.MeshBasicMaterial({ opacity: 0, transparent: true })
+ );
+ intersect_plane.rotation.x = Math.PI / -2;
+ scene.add( intersect_plane );
+
+ initEventHandling();
+
+ requestAnimationFrame( render );
+ scene.simulate();
+};
+
+render = function() {
+ requestAnimationFrame( render );
+ renderer.render( scene, camera );
+ render_stats.update();
+};
+
+createTower = (function() {
+ var block_length = 6, block_height = 1, block_width = 1.5, block_offset = 2,
+ block_geometry = new THREE.BoxGeometry( block_length, block_height, block_width );
+
+ return function() {
+ var i, j, rows = 16,
+ block;
+
+ for ( i = 0; i < rows; i++ ) {
+ for ( j = 0; j < 3; j++ ) {
+ block = new Physijs.BoxMesh( block_geometry, block_material );
+ block.position.y = (block_height / 2) + block_height * i;
+ if ( i % 2 === 0 ) {
+ block.rotation.y = Math.PI / 2.01; // #TODO: There's a bug somewhere when this is to close to 2
+ block.position.x = block_offset * j - ( block_offset * 3 / 2 - block_offset / 2 );
+ } else {
+ block.position.z = block_offset * j - ( block_offset * 3 / 2 - block_offset / 2 );
+ }
+ block.receiveShadow = true;
+ block.castShadow = true;
+ scene.add( block );
+ blocks.push( block );
+ }
+ }
+ }
+})();
+
+initEventHandling = (function() {
+ var _vector = new THREE.Vector3,
+ projector = new THREE.Projector(),
+ handleMouseDown, handleMouseMove, handleMouseUp;
+
+ handleMouseDown = function( evt ) {
+ var ray, intersections;
+
+ _vector.set(
+ ( evt.clientX / window.innerWidth ) * 2 - 1,
+ -( evt.clientY / window.innerHeight ) * 2 + 1,
+ 1
+ );
+
+ projector.unprojectVector( _vector, camera );
+
+ ray = new THREE.Raycaster( camera.position, _vector.sub( camera.position ).normalize() );
+ intersections = ray.intersectObjects( blocks );
+
+ if ( intersections.length > 0 ) {
+ selected_block = intersections[0].object;
+
+ _vector.set( 0, 0, 0 );
+ selected_block.setAngularFactor( _vector );
+ selected_block.setAngularVelocity( _vector );
+ selected_block.setLinearFactor( _vector );
+ selected_block.setLinearVelocity( _vector );
+
+ mouse_pos.copy( intersections[0].point );
+ block_offset.subVectors( selected_block.position, mouse_pos );
+
+ intersect_plane.position.y = mouse_pos.y;
+ }
+ };
+
+ handleMouseMove = function( evt ) {
+
+ var ray, intersection,
+ i, scalar;
+
+ if ( selected_block !== null ) {
+
+ _vector.set(
+ ( evt.clientX / window.innerWidth ) * 2 - 1,
+ -( evt.clientY / window.innerHeight ) * 2 + 1,
+ 1
+ );
+ projector.unprojectVector( _vector, camera );
+
+ ray = new THREE.Raycaster( camera.position, _vector.sub( camera.position ).normalize() );
+ intersection = ray.intersectObject( intersect_plane );
+ mouse_pos.copy( intersection[0].point );
+ }
+
+ };
+
+ handleMouseUp = function( evt ) {
+
+ if ( selected_block !== null ) {
+ _vector.set( 1, 1, 1 );
+ selected_block.setAngularFactor( _vector );
+ selected_block.setLinearFactor( _vector );
+
+ selected_block = null;
+ }
+
+ };
+
+ return function() {
+ renderer.domElement.addEventListener( 'mousedown', handleMouseDown );
+ renderer.domElement.addEventListener( 'mousemove', handleMouseMove );
+ renderer.domElement.addEventListener( 'mouseup', handleMouseUp );
+ };
+})();
+
+window.onload = initScene;
diff --git a/physijs/tests/memorytest-compound.ts b/physijs/tests/memorytest-compound.ts
new file mode 100644
index 000000000..0455b71f2
--- /dev/null
+++ b/physijs/tests/memorytest-compound.ts
@@ -0,0 +1,171 @@
+///
+///
+
+
+Physijs.scripts.worker = '../physijs_worker.js';
+Physijs.scripts.ammo = 'examples/js/ammo.js';
+
+var initScene, render, _boxes = [], spawnBox, inc_ready, renderer, render_stats, physics_stats, scene, ground_material, ground, light, camera;
+
+var cubes = [];
+var total_cubes = 0;
+var total_ready = 0;
+var max_on_screen = 100;
+var spawn_per_tick = 25;
+
+initScene = function() {
+ renderer = new THREE.WebGLRenderer({ antialias: true });
+ renderer.setSize( window.innerWidth, window.innerHeight );
+ renderer.shadowMapEnabled = true;
+ renderer.shadowMapSoft = true;
+ document.getElementById( 'viewport' ).appendChild( renderer.domElement );
+
+ render_stats = new Stats();
+ render_stats.domElement.style.position = 'absolute';
+ render_stats.domElement.style.top = '0px';
+ render_stats.domElement.style.zIndex = 100;
+ document.getElementById( 'viewport' ).appendChild( render_stats.domElement );
+
+ physics_stats = new Stats();
+ physics_stats.domElement.style.position = 'absolute';
+ physics_stats.domElement.style.top = '50px';
+ physics_stats.domElement.style.zIndex = 100;
+ document.getElementById( 'viewport' ).appendChild( physics_stats.domElement );
+
+ scene = new Physijs.Scene;
+ scene.setGravity(new THREE.Vector3( 0, -30, 0 ));
+ scene.addEventListener(
+ 'update',
+ function() {
+ scene.simulate( undefined, 1 );
+ physics_stats.update();
+ while(cubes.length > max_on_screen) {
+ scene.remove(cubes[0]);
+ cubes[0].geometry.dispose();
+ cubes[0].material.dispose();
+ cubes.splice( 0, 1 );
+ }
+ document.getElementById( 'totalcubecount' ).textContent = ( total_cubes.toString() );
+ document.getElementById( 'currentcubecount' ).textContent = ( cubes.length.toString() );
+ document.getElementById( 'totalobjects' ).textContent = ( scene.__objects.length );
+ if(total_cubes > total_ready){
+ return;
+ }
+ for (var i=0;i
+///
+
+
+Physijs.scripts.worker = '../physijs_worker.js';
+Physijs.scripts.ammo = 'examples/js/ammo.js';
+
+var initScene, render, _boxes = [], spawnBox, inc_ready, renderer, render_stats, physics_stats, scene, ground_material, ground, light, camera;
+
+var cubes = [];
+var total_cubes = 0;
+var total_ready = 0;
+var max_on_screen = 100;
+var spawn_per_tick = 25;
+
+initScene = function() {
+ renderer = new THREE.WebGLRenderer({ antialias: true });
+ renderer.setSize( window.innerWidth, window.innerHeight );
+ renderer.shadowMapEnabled = true;
+ renderer.shadowMapSoft = true;
+ document.getElementById( 'viewport' ).appendChild( renderer.domElement );
+
+ render_stats = new Stats();
+ render_stats.domElement.style.position = 'absolute';
+ render_stats.domElement.style.top = '0px';
+ render_stats.domElement.style.zIndex = 100;
+ document.getElementById( 'viewport' ).appendChild( render_stats.domElement );
+
+ physics_stats = new Stats();
+ physics_stats.domElement.style.position = 'absolute';
+ physics_stats.domElement.style.top = '50px';
+ physics_stats.domElement.style.zIndex = 100;
+ document.getElementById( 'viewport' ).appendChild( physics_stats.domElement );
+
+ scene = new Physijs.Scene;
+ scene.setGravity(new THREE.Vector3( 0, -30, 0 ));
+ scene.addEventListener(
+ 'update',
+ function() {
+ scene.simulate( undefined, 1 );
+ physics_stats.update();
+ while(cubes.length > max_on_screen) {
+ scene.remove(cubes[0]);
+ cubes[0].geometry.dispose();
+ cubes[0].material.dispose();
+ cubes.splice( 0, 1 );
+ }
+ document.getElementById( 'totalcubecount' ).textContent = ( total_cubes.toString() );
+ document.getElementById( 'currentcubecount' ).textContent = ( cubes.length.toString() );
+ document.getElementById( 'totalobjects' ).textContent = ( scene.__objects.length );
+ if(total_cubes > total_ready){
+ return;
+ }
+ for (var i=0;i
+///
+
+
+Physijs.scripts.worker = '../physijs_worker.js';
+Physijs.scripts.ammo = 'examples/js/ammo.js';
+
+var initScene, render, _boxes = [], spawnBox, inc_ready, renderer, render_stats, physics_stats, scene, ground_material, ground, light, camera;
+
+var cubes = [];
+var total_cubes = 0;
+var total_ready = 0;
+var max_on_screen = 100;
+var spawn_per_tick = 25;
+
+initScene = function() {
+ renderer = new THREE.WebGLRenderer({ antialias: true });
+ renderer.setSize( window.innerWidth, window.innerHeight );
+ renderer.shadowMapEnabled = true;
+ renderer.shadowMapSoft = true;
+ document.getElementById( 'viewport' ).appendChild( renderer.domElement );
+
+ render_stats = new Stats();
+ render_stats.domElement.style.position = 'absolute';
+ render_stats.domElement.style.top = '0px';
+ render_stats.domElement.style.zIndex = 100;
+ document.getElementById( 'viewport' ).appendChild( render_stats.domElement );
+
+ physics_stats = new Stats();
+ physics_stats.domElement.style.position = 'absolute';
+ physics_stats.domElement.style.top = '50px';
+ physics_stats.domElement.style.zIndex = 100;
+ document.getElementById( 'viewport' ).appendChild( physics_stats.domElement );
+
+ scene = new Physijs.Scene;
+ scene.setGravity(new THREE.Vector3( 0, -30, 0 ));
+ scene.addEventListener(
+ 'update',
+ function() {
+ scene.simulate( undefined, 1 );
+ physics_stats.update();
+ while(cubes.length > max_on_screen) {
+ scene.remove(cubes[0]);
+ cubes[0].geometry.dispose();
+ cubes[0].material.dispose();
+ cubes.splice( 0, 1 );
+ }
+ document.getElementById( 'totalcubecount' ).textContent = ( total_cubes.toString() );
+ document.getElementById( 'currentcubecount' ).textContent = ( cubes.length.toString() );
+ document.getElementById( 'totalobjects' ).textContent = ( scene.__objects.length );
+ if(total_cubes > total_ready){
+ return;
+ }
+ for (var i=0;i
+///
+
+
+var TWEEN: any;
+var SimplexNoise: any;
+
+
+Physijs.scripts.worker = '../physijs_worker.js';
+Physijs.scripts.ammo = 'examples/js/ammo.js';
+
+var initScene, render, createShape,
+ renderer, render_stats, physics_stats, scene, light, ground, ground_material, camera;
+
+initScene = function() {
+ TWEEN.start();
+
+ renderer = new THREE.WebGLRenderer({ antialias: true });
+ renderer.setSize( window.innerWidth, window.innerHeight );
+ renderer.shadowMapEnabled = true;
+ renderer.shadowMapSoft = true;
+ document.getElementById( 'viewport' ).appendChild( renderer.domElement );
+
+ render_stats = new Stats();
+ render_stats.domElement.style.position = 'absolute';
+ render_stats.domElement.style.top = '0px';
+ render_stats.domElement.style.zIndex = 100;
+ document.getElementById( 'viewport' ).appendChild( render_stats.domElement );
+
+ physics_stats = new Stats();
+ physics_stats.domElement.style.position = 'absolute';
+ physics_stats.domElement.style.top = '50px';
+ physics_stats.domElement.style.zIndex = 100;
+ document.getElementById( 'viewport' ).appendChild( physics_stats.domElement );
+
+ scene = new Physijs.Scene({ fixedTimeStep: 1 / 120 });
+ scene.setGravity(new THREE.Vector3( 0, -30, 0 ));
+ scene.addEventListener(
+ 'update',
+ function() {
+ scene.simulate( undefined, 2 );
+ physics_stats.update();
+ }
+ );
+
+ camera = new THREE.PerspectiveCamera(
+ 35,
+ window.innerWidth / window.innerHeight,
+ 1,
+ 1000
+ );
+ camera.position.set( 60, 50, 60 );
+ camera.lookAt( scene.position );
+ scene.add( camera );
+
+ // Light
+ light = new THREE.DirectionalLight( 0xFFFFFF );
+ light.position.set( 20, 40, -15 );
+ light.target.position.copy( scene.position );
+ light.castShadow = true;
+ light.shadowCameraLeft = -60;
+ light.shadowCameraTop = -60;
+ light.shadowCameraRight = 60;
+ light.shadowCameraBottom = 60;
+ light.shadowCameraNear = 20;
+ light.shadowCameraFar = 200;
+ light.shadowBias = -.0001
+ light.shadowMapWidth = light.shadowMapHeight = 2048;
+ light.shadowDarkness = .7;
+ scene.add( light );
+
+ // Materials
+ ground_material = Physijs.createMaterial(
+ new THREE.MeshLambertMaterial({ map: THREE.ImageUtils.loadTexture( 'images/rocks.jpg' ) }),
+ .8, // high friction
+ .4 // low restitution
+ );
+ ground_material.map.wrapS = ground_material.map.wrapT = THREE.RepeatWrapping;
+ ground_material.map.repeat.set( 2.5, 2.5 );
+
+ // Ground
+ ground = new Physijs.BoxMesh(
+ new THREE.BoxGeometry(50, 1, 50),
+ //new THREE.PlaneGeometry(50, 50),
+ ground_material,
+ 0 // mass
+ );
+ ground.receiveShadow = true;
+ scene.add( ground );
+
+ // Bumpers
+ var bumper,
+ bumper_geom = new THREE.BoxGeometry(2, 1, 50);
+
+ bumper = new Physijs.BoxMesh( bumper_geom, ground_material, 0 );
+ bumper.position.y = 1;
+ bumper.position.x = -24;
+ bumper.receiveShadow = true;
+ bumper.castShadow = true;
+ scene.add( bumper );
+
+ bumper = new Physijs.BoxMesh( bumper_geom, ground_material, 0 );
+ bumper.position.y = 1;
+ bumper.position.x = 24;
+ bumper.receiveShadow = true;
+ bumper.castShadow = true;
+ scene.add( bumper );
+
+ bumper = new Physijs.BoxMesh( bumper_geom, ground_material, 0 );
+ bumper.position.y = 1;
+ bumper.position.z = -24;
+ bumper.rotation.y = Math.PI / 2;
+ bumper.receiveShadow = true;
+ bumper.castShadow = true;
+ scene.add( bumper );
+
+ bumper = new Physijs.BoxMesh( bumper_geom, ground_material, 0 );
+ bumper.position.y = 1;
+ bumper.position.z = 24;
+ bumper.rotation.y = Math.PI / 2;
+ bumper.receiveShadow = true;
+ bumper.castShadow = true;
+ scene.add( bumper );
+
+ requestAnimationFrame( render );
+ scene.simulate();
+
+ createShape();
+};
+
+render = function() {
+ requestAnimationFrame( render );
+ renderer.render( scene, camera );
+ render_stats.update();
+};
+
+createShape = (function() {
+ var addshapes = true,
+ shapes = 0,
+ box_geometry = new THREE.BoxGeometry( 3, 3, 3 ),
+ sphere_geometry = new THREE.SphereGeometry( 1.5, 32, 32 ),
+ cylinder_geometry = new THREE.CylinderGeometry( 2, 2, 1, 32 ),
+ cone_geometry = new THREE.CylinderGeometry( 0, 2, 4, 32 ),
+ octahedron_geometry = new THREE.OctahedronGeometry( 1.7, 1 ),
+ torus_geometry = new THREE.TorusKnotGeometry ( 1.7, .2, 32, 4 ),
+ doCreateShape;
+
+ setTimeout(
+ function addListener() {
+ var button = document.getElementById( 'stop' );
+ if ( button ) {
+ button.addEventListener( 'click', function() { addshapes = false; } );
+ } else {
+ setTimeout( addListener );
+ }
+ }
+ );
+
+ doCreateShape = function() {
+ var shape, material = new THREE.MeshLambertMaterial({ opacity: 0, transparent: true });
+
+ switch ( Math.floor(Math.random() * 6) ) {
+ case 0:
+ shape = new Physijs.BoxMesh(
+ box_geometry,
+ material
+ );
+ break;
+
+ case 1:
+ shape = new Physijs.SphereMesh(
+ sphere_geometry,
+ material,
+ undefined
+ );
+ break;
+
+ case 2:
+ shape = new Physijs.CylinderMesh(
+ cylinder_geometry,
+ material
+ );
+ break;
+
+ case 3:
+ shape = new Physijs.ConeMesh(
+ cone_geometry,
+ material
+ );
+ break;
+
+ case 4:
+ shape = new Physijs.ConvexMesh(
+ octahedron_geometry,
+ material
+ );
+ break;
+
+ case 5:
+ shape = new Physijs.ConvexMesh(
+ torus_geometry,
+ material
+ );
+ break;
+ }
+
+ shape.material.color.setRGB( Math.random() * 100 / 100, Math.random() * 100 / 100, Math.random() * 100 / 100 );
+ shape.castShadow = true;
+ shape.receiveShadow = true;
+
+ shape.position.set(
+ Math.random() * 30 - 15,
+ 20,
+ Math.random() * 30 - 15
+ );
+
+ shape.rotation.set(
+ Math.random() * Math.PI,
+ Math.random() * Math.PI,
+ Math.random() * Math.PI
+ );
+
+ if ( addshapes ) {
+ shape.addEventListener( 'ready', createShape );
+ }
+ scene.add( shape );
+
+ new TWEEN.Tween(shape.material).to({opacity: 1}, 500).start();
+
+ document.getElementById( 'shapecount' ).textContent = ( ++shapes ) + ' shapes created';
+ };
+
+ return function() {
+ setTimeout( doCreateShape, 250 );
+ };
+})();
+
+window.onload = initScene;
diff --git a/physijs/tests/vehicle.ts b/physijs/tests/vehicle.ts
new file mode 100644
index 000000000..1b11066fe
--- /dev/null
+++ b/physijs/tests/vehicle.ts
@@ -0,0 +1,254 @@
+///
+///
+
+var TWEEN: any;
+var SimplexNoise: any;
+
+
+Physijs.scripts.worker = '../physijs_worker.js';
+Physijs.scripts.ammo = 'examples/js/ammo.js';
+
+var initScene, render,
+ ground_material, box_material,
+ projector, renderer, render_stats, physics_stats, scene, ground, light, camera,
+ vehicle_body, vehicle;
+
+initScene = function() {
+ projector = new THREE.Projector;
+
+ renderer = new THREE.WebGLRenderer({ antialias: true });
+ renderer.setSize( window.innerWidth, window.innerHeight );
+ renderer.shadowMapEnabled = true;
+ renderer.shadowMapSoft = true;
+ document.getElementById( 'viewport' ).appendChild( renderer.domElement );
+
+ render_stats = new Stats();
+ render_stats.domElement.style.position = 'absolute';
+ render_stats.domElement.style.top = '1px';
+ render_stats.domElement.style.zIndex = 100;
+ document.getElementById( 'viewport' ).appendChild( render_stats.domElement );
+
+ physics_stats = new Stats();
+ physics_stats.domElement.style.position = 'absolute';
+ physics_stats.domElement.style.top = '50px';
+ physics_stats.domElement.style.zIndex = 100;
+ document.getElementById( 'viewport' ).appendChild( physics_stats.domElement );
+
+ scene = new Physijs.Scene;
+ scene.setGravity(new THREE.Vector3( 0, -30, 0 ));
+ scene.addEventListener(
+ 'update',
+ function() {
+
+ if ( input && vehicle ) {
+ if ( input.direction !== null ) {
+ input.steering += input.direction / 50;
+ if ( input.steering < -.6 ) input.steering = -.6;
+ if ( input.steering > .6 ) input.steering = .6;
+ }
+ vehicle.setSteering( input.steering, 0 );
+ vehicle.setSteering( input.steering, 1 );
+
+ if ( input.power === true ) {
+ vehicle.applyEngineForce( 300 );
+ } else if ( input.power === false ) {
+ vehicle.setBrake( 20, 2 );
+ vehicle.setBrake( 20, 3 );
+ } else {
+ vehicle.applyEngineForce( 0 );
+ }
+ }
+
+ scene.simulate( undefined, 2 );
+ physics_stats.update();
+ }
+ );
+
+ camera = new THREE.PerspectiveCamera(
+ 35,
+ window.innerWidth / window.innerHeight,
+ 1,
+ 1000
+ );
+ scene.add( camera );
+
+ // Light
+ light = new THREE.DirectionalLight( 0xFFFFFF );
+ light.position.set( 20, 20, -15 );
+ light.target.position.copy( scene.position );
+ light.castShadow = true;
+ light.shadowCameraLeft = -150;
+ light.shadowCameraTop = -150;
+ light.shadowCameraRight = 150;
+ light.shadowCameraBottom = 150;
+ light.shadowCameraNear = 20;
+ light.shadowCameraFar = 400;
+ light.shadowBias = -.0001
+ light.shadowMapWidth = light.shadowMapHeight = 2048;
+ light.shadowDarkness = .7;
+ scene.add( light );
+
+
+ var input;
+
+
+ // Materials
+ ground_material = Physijs.createMaterial(
+ new THREE.MeshLambertMaterial({ map: THREE.ImageUtils.loadTexture( 'images/rocks.jpg' ) }),
+ .8, // high friction
+ .4 // low restitution
+ );
+ ground_material.map.wrapS = ground_material.map.wrapT = THREE.RepeatWrapping;
+ ground_material.map.repeat.set( 3, 3 );
+
+ box_material = Physijs.createMaterial(
+ new THREE.MeshLambertMaterial({ map: THREE.ImageUtils.loadTexture( 'images/plywood.jpg' ) }),
+ .4, // low friction
+ .6 // high restitution
+ );
+ box_material.map.wrapS = ground_material.map.wrapT = THREE.RepeatWrapping;
+ box_material.map.repeat.set( .25, .25 );
+
+ // Ground
+ var NoiseGen = new SimplexNoise;
+
+ var ground_geometry = new THREE.PlaneGeometry( 300, 300, 100, 100 );
+ for ( var i = 0; i < ground_geometry.vertices.length; i++ ) {
+ var vertex = ground_geometry.vertices[i];
+ //vertex.y = NoiseGen.noise( vertex.x / 30, vertex.z / 30 ) * 1;
+ }
+ ground_geometry.computeFaceNormals();
+ ground_geometry.computeVertexNormals();
+
+ // If your plane is not square as far as face count then the HeightfieldMesh
+ // takes two more arguments at the end: # of x faces and # of z faces that were passed to THREE.PlaneMaterial
+ ground = new Physijs.HeightfieldMesh(
+ ground_geometry,
+ ground_material,
+ 0 // mass
+ );
+ ground.rotation.x = -Math.PI / 2;
+ ground.receiveShadow = true;
+ scene.add( ground );
+
+ for ( i = 0; i < 50; i++ ) {
+ var size = Math.random() * 2 + .5;
+ var box = new Physijs.BoxMesh(
+ new THREE.BoxGeometry( size, size, size ),
+ box_material
+ );
+ box.castShadow = box.receiveShadow = true;
+ box.position.set(
+ Math.random() * 25 - 50,
+ 5,
+ Math.random() * 25 - 50
+ );
+ scene.add( box )
+ }
+
+
+ var loader = new THREE.JSONLoader();
+
+ loader.load( "models/mustang.js", function( car, car_materials ) {
+ loader.load( "models/mustang_wheel.js", function( wheel, wheel_materials ) {
+ var mesh = new Physijs.BoxMesh(
+ car,
+ new THREE.MeshFaceMaterial( car_materials )
+ );
+ mesh.position.y = 2;
+ mesh.castShadow = mesh.receiveShadow = true;
+
+ vehicle = new Physijs.Vehicle(mesh, new Physijs.VehicleTuning(
+ 10.88,
+ 1.83,
+ 0.28,
+ 500,
+ 10.5,
+ 6000
+ ));
+ scene.add( vehicle );
+
+ var wheel_material = new THREE.MeshFaceMaterial( wheel_materials );
+
+ for ( var i = 0; i < 4; i++ ) {
+ vehicle.addWheel(
+ wheel,
+ wheel_material,
+ new THREE.Vector3(
+ i % 2 === 0 ? -1.6 : 1.6,
+ -1,
+ i < 2 ? 3.3 : -3.2
+ ),
+ new THREE.Vector3( 0, -1, 0 ),
+ new THREE.Vector3( -1, 0, 0 ),
+ 0.5,
+ 0.7,
+ i < 2 ? false : true
+ );
+ }
+
+ input = {
+ power: null,
+ direction: null,
+ steering: 0
+ };
+ document.addEventListener('keydown', function( ev ) {
+ switch ( ev.keyCode ) {
+ case 37: // left
+ input.direction = 1;
+ break;
+
+ case 38: // forward
+ input.power = true;
+ break;
+
+ case 39: // right
+ input.direction = -1;
+ break;
+
+ case 40: // back
+ input.power = false;
+ break;
+ }
+ });
+ document.addEventListener('keyup', function( ev ) {
+ switch ( ev.keyCode ) {
+ case 37: // left
+ input.direction = null;
+ break;
+
+ case 38: // forward
+ input.power = null;
+ break;
+
+ case 39: // right
+ input.direction = null;
+ break;
+
+ case 40: // back
+ input.power = null;
+ break;
+ }
+ });
+ });
+ });
+
+ requestAnimationFrame( render );
+ scene.simulate();
+};
+
+
+render = function() {
+ requestAnimationFrame( render );
+ if ( vehicle ) {
+ camera.position.copy( vehicle.mesh.position ).add( new THREE.Vector3( 40, 25, 40 ) );
+ camera.lookAt( vehicle.mesh.position );
+
+ light.target.position.copy( vehicle.mesh.position );
+ light.position.addVectors( light.target.position, new THREE.Vector3( 20, 20, -15 ) );
+ }
+ renderer.render( scene, camera );
+ render_stats.update();
+};
+
+window.onload = initScene;