|
|
|
<!------- TRANSITION PAGES -------> |
|
|
|
<div id="landing_page_div" class="display_page"> |
|
<div id="landing_logo_div"> |
|
<img id="logo_landing" src="https://s3-us-west-2.amazonaws.com/s.cdpn.io/409445/bus_derby_logo.svg"> |
|
<img id="button_play" src="https://s3-us-west-2.amazonaws.com/s.cdpn.io/409445/bus_button_play.svg"> |
|
</div> |
|
|
|
<!-- AD --> |
|
<div id="ad_div"> |
|
<a href="https://codepen.io/matthewmain/full/MxwBmo" target="_blank"> |
|
<img id="ad_svg" src="https://s3-us-west-2.amazonaws.com/s.cdpn.io/409445/kts_ad.svg"> |
|
</a> |
|
</div> |
|
<style> |
|
#ad_div { |
|
position: fixed; |
|
width: 15%; |
|
bottom: 1.5%; |
|
right: 1.5%; |
|
} |
|
#ad_svg { |
|
width: 100%; |
|
} |
|
</style> |
|
|
|
</div> |
|
|
|
<!-- animated loader page --> |
|
<div id="loading_animation_page" class="display_page"> |
|
<div id="loading_animation_div"> |
|
<svg id="loading_animation_svg" viewBox="0 0 100 100"> |
|
<line class="loading_animation_lines" id="loading_animation_line_1" x1=5% y1=45% x2=95% y2=45% /> |
|
<line class="loading_animation_lines" id="loading_animation_line_2" x1=5% y1=50% x2=95% y2=50% /> |
|
<line class="loading_animation_lines" id="loading_animation_line_3" x1=19% y1=55% x2=81% y2=55% /> |
|
</svg> |
|
<img id="loading_animation_insignia" src="https://s3-us-west-2.amazonaws.com/s.cdpn.io/409445/bus_insignia.svg"> |
|
</div> |
|
</div> |
|
|
|
<!-- round win announcement page --> |
|
<div id="round_win_page_div" class="display_page announcement_page"> |
|
<div id="round_win_card_div" class="card_div"> |
|
<img id="round_win_card" class="card" src="https://s3-us-west-2.amazonaws.com/s.cdpn.io/409445/bus_round_win_card_gretchen.svg"> |
|
<img id="round_score_green" class="round_score green_score" src="https://s3-us-west-2.amazonaws.com/s.cdpn.io/409445/bus_1of3_green.svg"> |
|
<img id="round_score_red" class="round_score red_score" src="https://s3-us-west-2.amazonaws.com/s.cdpn.io/409445/bus_0of3_red.svg"> |
|
<img id="button_play_next_round" class="card_button" src="https://s3-us-west-2.amazonaws.com/s.cdpn.io/409445/bus_button_play_next_round.svg"> |
|
</div> |
|
</div> |
|
|
|
<!-- round draw announcement page --> |
|
<div id="round_draw_page_div" class="display_page announcement_page"> |
|
<div id="round_draw_card_div" class="card_div"> |
|
<img id="round_draw_card" class="card" src="https://s3-us-west-2.amazonaws.com/s.cdpn.io/409445/bus_round_draw_card.svg"> |
|
<img id="button_replay_round" class="card_button" src="https://s3-us-west-2.amazonaws.com/s.cdpn.io/409445/bus_button_replay_round.svg"> |
|
</div> |
|
</div> |
|
|
|
<!-- game win announcement pages --> |
|
<div id="game_win_gretchen_page_div" class="display_page announcement_page"> |
|
<div id="game_win_gretchen_card_div" class="card_div"> |
|
<img id="game_win_gretchen_card" class="card" src="https://s3-us-west-2.amazonaws.com/s.cdpn.io/409445/bus_game_win_card_gretchen.svg"> |
|
<img class="card_button button_new_game" src="https://s3-us-west-2.amazonaws.com/s.cdpn.io/409445/bus_button_new_game.svg"> |
|
</div> |
|
</div> |
|
|
|
<div id="game_win_bertha_page_div" class="display_page announcement_page"> |
|
<div id="game_win_bertha_card_div" class="card_div"> |
|
<img id="game_win_bertha_card" class="card" src="https://s3-us-west-2.amazonaws.com/s.cdpn.io/409445/bus_game_win_card_bertha.svg"> |
|
<img class="card_button button_new_game" src="https://s3-us-west-2.amazonaws.com/s.cdpn.io/409445/bus_button_new_game.svg"> |
|
</div> |
|
</div> |
|
|
|
|
|
|
|
|
|
<!------- UI -------> |
|
|
|
<!-- logo --> |
|
<div id="logo_div"> |
|
<img id="logo" src="https://s3-us-west-2.amazonaws.com/s.cdpn.io/409445/bus_derby_logo.svg"> |
|
<a href="https://matthewma.in" target="_blank"><img id="copyright" src="https://s3-us-west-2.amazonaws.com/s.cdpn.io/409445/bus_copyright.svg"></a> |
|
</div> |
|
|
|
|
|
<!-- scoreboard --> |
|
<div id="scoreboard_div"> |
|
<img id="scoreboard_img" src="https://s3-us-west-2.amazonaws.com/s.cdpn.io/409445/bus_scoreboard.svg"> |
|
<img id="board_score_green" class="board_score green_score" src="https://s3-us-west-2.amazonaws.com/s.cdpn.io/409445/bus_0of3_green.svg"> |
|
<img id="board_score_red" class="board_score red_score" src="https://s3-us-west-2.amazonaws.com/s.cdpn.io/409445/bus_0of3_red.svg"> |
|
</div> |
|
|
|
<!-- buttons --> |
|
<div id="buttons_div"> |
|
<img id="button_restart" class="buttons_items button_restart" title="restart the game" src="https://s3-us-west-2.amazonaws.com/s.cdpn.io/409445/bus_button_restart.svg"> |
|
<img class="buttons_items button_divider" src="https://s3-us-west-2.amazonaws.com/s.cdpn.io/409445/bus_button_divider.svg"> |
|
<img id="button_draw" class="buttons_items button_draw" title="declare match a draw" src="https://s3-us-west-2.amazonaws.com/s.cdpn.io/409445/bus_button_draw.svg"> |
|
</div> |
|
|
|
<!-- nav --> |
|
<img class="nav left_nav" src="https://s3-us-west-2.amazonaws.com/s.cdpn.io/409445/bus_nav_left.svg"> |
|
<img class="nav right_nav" src="https://s3-us-west-2.amazonaws.com/s.cdpn.io/409445/bus_nav_right.svg"> |
|
|
|
|
|
|
|
<!------- LIBRARIES -------> |
|
|
|
<!-- jQuery source --> |
|
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script> |
|
<!-- three.js source --> |
|
<script src='https://threejs.org/build/three.min.js'></script> |
|
<!-- GLTFLoader.js source --> |
|
<script src="https://cdn.rawgit.com/mrdoob/three.js/master/examples/js/loaders/GLTFLoader.js"></script> |
|
<!-- physi.js source --> |
|
<script src='https://chandlerprall.github.io/Physijs/physi.js'></script> |
|
<!-- full physijs_worker.js contents in a script (needed so worker can be used in codepen) --> |
|
<script id="physijs_worker" type="javascript/worker"> |
|
|
|
|
|
var transferableMessage = self.webkitPostMessage || self.postMessage, |
|
|
|
// enum |
|
MESSAGE_TYPES = { |
|
WORLDREPORT: 0, |
|
COLLISIONREPORT: 1, |
|
VEHICLEREPORT: 2, |
|
CONSTRAINTREPORT: 3 |
|
}, |
|
|
|
// temp variables |
|
_object, |
|
_vector, |
|
_transform, |
|
|
|
// functions |
|
public_functions = {}, |
|
getShapeFromCache, |
|
setShapeCache, |
|
createShape, |
|
reportWorld, |
|
reportVehicles, |
|
reportCollisions, |
|
reportConstraints, |
|
|
|
// world variables |
|
fixedTimeStep, // used when calling stepSimulation |
|
rateLimit, // sets whether or not to sync the simulation rate with fixedTimeStep |
|
last_simulation_time, |
|
last_simulation_duration = 0, |
|
world, |
|
transform, |
|
_vec3_1, |
|
_vec3_2, |
|
_vec3_3, |
|
_quat, |
|
// private cache |
|
_objects = {}, |
|
_vehicles = {}, |
|
_constraints = {}, |
|
_materials = {}, |
|
_objects_ammo = {}, |
|
_num_objects = 0, |
|
_num_wheels = 0, |
|
_num_constraints = 0, |
|
_object_shapes = {}, |
|
|
|
// The following objects are to track objects that ammo.js doesn't clean |
|
// up. All are cleaned up when they're corresponding body is destroyed. |
|
// Unfortunately, it's very difficult to get at these objects from the |
|
// body, so we have to track them ourselves. |
|
_motion_states = {}, |
|
// Don't need to worry about it for cached shapes. |
|
_noncached_shapes = {}, |
|
// A body with a compound shape always has a regular shape as well, so we |
|
// have track them separately. |
|
_compound_shapes = {}, |
|
|
|
// object reporting |
|
REPORT_CHUNKSIZE, // report array is increased in increments of this chunk size |
|
|
|
WORLDREPORT_ITEMSIZE = 14, // how many float values each reported item needs |
|
worldreport, |
|
|
|
COLLISIONREPORT_ITEMSIZE = 5, // one float for each object id, and a Vec3 contact normal |
|
collisionreport, |
|
|
|
VEHICLEREPORT_ITEMSIZE = 9, // vehicle id, wheel index, 3 for position, 4 for rotation |
|
vehiclereport, |
|
|
|
CONSTRAINTREPORT_ITEMSIZE = 6, // constraint id, offset object, offset, applied impulse |
|
constraintreport; |
|
|
|
var ab = new ArrayBuffer( 1 ); |
|
|
|
transferableMessage( ab, [ab] ); |
|
var SUPPORT_TRANSFERABLE = ( ab.byteLength === 0 ); |
|
|
|
getShapeFromCache = function ( cache_key ) { |
|
if ( _object_shapes[ cache_key ] !== undefined ) { |
|
return _object_shapes[ cache_key ]; |
|
} |
|
return null; |
|
}; |
|
|
|
setShapeCache = function ( cache_key, shape ) { |
|
_object_shapes[ cache_key ] = shape; |
|
} |
|
|
|
createShape = function( description ) { |
|
var cache_key, shape; |
|
|
|
_transform.setIdentity(); |
|
switch ( description.type ) { |
|
case 'plane': |
|
cache_key = 'plane_' + description.normal.x + '_' + description.normal.y + '_' + description.normal.z; |
|
if ( ( shape = getShapeFromCache( cache_key ) ) === null ) { |
|
_vec3_1.setX(description.normal.x); |
|
_vec3_1.setY(description.normal.y); |
|
_vec3_1.setZ(description.normal.z); |
|
shape = new Ammo.btStaticPlaneShape(_vec3_1, 0 ); |
|
setShapeCache( cache_key, shape ); |
|
} |
|
break; |
|
|
|
case 'box': |
|
cache_key = 'box_' + description.width + '_' + description.height + '_' + description.depth; |
|
if ( ( shape = getShapeFromCache( cache_key ) ) === null ) { |
|
_vec3_1.setX(description.width / 2); |
|
_vec3_1.setY(description.height / 2); |
|
_vec3_1.setZ(description.depth / 2); |
|
shape = new Ammo.btBoxShape(_vec3_1); |
|
setShapeCache( cache_key, shape ); |
|
} |
|
break; |
|
|
|
case 'sphere': |
|
cache_key = 'sphere_' + description.radius; |
|
if ( ( shape = getShapeFromCache( cache_key ) ) === null ) { |
|
shape = new Ammo.btSphereShape( description.radius ); |
|
setShapeCache( cache_key, shape ); |
|
} |
|
break; |
|
|
|
case 'cylinder': |
|
cache_key = 'cylinder_' + description.width + '_' + description.height + '_' + description.depth; |
|
if ( ( shape = getShapeFromCache( cache_key ) ) === null ) { |
|
_vec3_1.setX(description.width / 2); |
|
_vec3_1.setY(description.height / 2); |
|
_vec3_1.setZ(description.depth / 2); |
|
shape = new Ammo.btCylinderShape(_vec3_1); |
|
setShapeCache( cache_key, shape ); |
|
} |
|
break; |
|
|
|
case 'capsule': |
|
cache_key = 'capsule_' + description.radius + '_' + description.height; |
|
if ( ( shape = getShapeFromCache( cache_key ) ) === null ) { |
|
// In Bullet, capsule height excludes the end spheres |
|
shape = new Ammo.btCapsuleShape( description.radius, description.height - 2 * description.radius ); |
|
setShapeCache( cache_key, shape ); |
|
} |
|
break; |
|
|
|
case 'cone': |
|
cache_key = 'cone_' + description.radius + '_' + description.height; |
|
if ( ( shape = getShapeFromCache( cache_key ) ) === null ) { |
|
shape = new Ammo.btConeShape( description.radius, description.height ); |
|
setShapeCache( cache_key, shape ); |
|
} |
|
break; |
|
|
|
case 'concave': |
|
var i, triangle, triangle_mesh = new Ammo.btTriangleMesh; |
|
if (!description.triangles.length) return false |
|
|
|
for ( i = 0; i < description.triangles.length; i++ ) { |
|
triangle = description.triangles[i]; |
|
|
|
_vec3_1.setX(triangle[0].x); |
|
_vec3_1.setY(triangle[0].y); |
|
_vec3_1.setZ(triangle[0].z); |
|
|
|
_vec3_2.setX(triangle[1].x); |
|
_vec3_2.setY(triangle[1].y); |
|
_vec3_2.setZ(triangle[1].z); |
|
|
|
_vec3_3.setX(triangle[2].x); |
|
_vec3_3.setY(triangle[2].y); |
|
_vec3_3.setZ(triangle[2].z); |
|
|
|
triangle_mesh.addTriangle( |
|
_vec3_1, |
|
_vec3_2, |
|
_vec3_3, |
|
true |
|
); |
|
} |
|
|
|
shape = new Ammo.btBvhTriangleMeshShape( |
|
triangle_mesh, |
|
true, |
|
true |
|
); |
|
_noncached_shapes[description.id] = shape; |
|
break; |
|
|
|
case 'convex': |
|
var i, point, shape = new Ammo.btConvexHullShape; |
|
for ( i = 0; i < description.points.length; i++ ) { |
|
point = description.points[i]; |
|
|
|
_vec3_1.setX(point.x); |
|
_vec3_1.setY(point.y); |
|
_vec3_1.setZ(point.z); |
|
|
|
shape.addPoint(_vec3_1); |
|
|
|
} |
|
_noncached_shapes[description.id] = shape; |
|
break; |
|
|
|
case 'heightfield': |
|
|
|
var ptr = Ammo.allocate(4 * description.xpts * description.ypts, "float", Ammo.ALLOC_NORMAL); |
|
|
|
for (var f = 0; f < description.points.length; f++) { |
|
Ammo.setValue(ptr + f, description.points[f] , 'float'); |
|
} |
|
|
|
shape = new Ammo.btHeightfieldTerrainShape( |
|
description.xpts, |
|
description.ypts, |
|
ptr, |
|
1, |
|
-description.absMaxHeight, |
|
description.absMaxHeight, |
|
2, |
|
0, |
|
false |
|
); |
|
|
|
_vec3_1.setX(description.xsize/(description.xpts - 1)); |
|
_vec3_1.setY(description.ysize/(description.ypts - 1)); |
|
_vec3_1.setZ(1); |
|
|
|
shape.setLocalScaling(_vec3_1); |
|
_noncached_shapes[description.id] = shape; |
|
break; |
|
|
|
default: |
|
// Not recognized |
|
return; |
|
break; |
|
} |
|
|
|
return shape; |
|
}; |
|
|
|
public_functions.init = function( params ) { |
|
importScripts( params.ammo ); |
|
|
|
_transform = new Ammo.btTransform; |
|
_vec3_1 = new Ammo.btVector3(0,0,0); |
|
_vec3_2 = new Ammo.btVector3(0,0,0); |
|
_vec3_3 = new Ammo.btVector3(0,0,0); |
|
_quat = new Ammo.btQuaternion(0,0,0,0); |
|
|
|
REPORT_CHUNKSIZE = params.reportsize || 50; |
|
if ( SUPPORT_TRANSFERABLE ) { |
|
// Transferable messages are supported, take advantage of them with TypedArrays |
|
worldreport = new Float32Array(2 + REPORT_CHUNKSIZE * WORLDREPORT_ITEMSIZE); // message id + # of objects to report + chunk size * # of values per object |
|
collisionreport = new Float32Array(2 + REPORT_CHUNKSIZE * COLLISIONREPORT_ITEMSIZE); // message id + # of collisions to report + chunk size * # of values per object |
|
vehiclereport = new Float32Array(2 + REPORT_CHUNKSIZE * VEHICLEREPORT_ITEMSIZE); // message id + # of vehicles to report + chunk size * # of values per object |
|
constraintreport = new Float32Array(2 + REPORT_CHUNKSIZE * CONSTRAINTREPORT_ITEMSIZE); // message id + # of constraints to report + chunk size * # of values per object |
|
} else { |
|
// Transferable messages are not supported, send data as normal arrays |
|
worldreport = []; |
|
collisionreport = []; |
|
vehiclereport = []; |
|
constraintreport = []; |
|
} |
|
worldreport[0] = MESSAGE_TYPES.WORLDREPORT; |
|
collisionreport[0] = MESSAGE_TYPES.COLLISIONREPORT; |
|
vehiclereport[0] = MESSAGE_TYPES.VEHICLEREPORT; |
|
constraintreport[0] = MESSAGE_TYPES.CONSTRAINTREPORT; |
|
|
|
var collisionConfiguration = new Ammo.btDefaultCollisionConfiguration, |
|
dispatcher = new Ammo.btCollisionDispatcher( collisionConfiguration ), |
|
solver = new Ammo.btSequentialImpulseConstraintSolver, |
|
broadphase; |
|
|
|
if ( !params.broadphase ) params.broadphase = { type: 'dynamic' }; |
|
switch ( params.broadphase.type ) { |
|
case 'sweepprune': |
|
|
|
_vec3_1.setX(params.broadphase.aabbmin.x); |
|
_vec3_1.setY(params.broadphase.aabbmin.y); |
|
_vec3_1.setZ(params.broadphase.aabbmin.z); |
|
|
|
_vec3_2.setX(params.broadphase.aabbmax.x); |
|
_vec3_2.setY(params.broadphase.aabbmax.y); |
|
_vec3_2.setZ(params.broadphase.aabbmax.z); |
|
|
|
broadphase = new Ammo.btAxisSweep3( |
|
_vec3_1, |
|
_vec3_2 |
|
); |
|
|
|
break; |
|
|
|
case 'dynamic': |
|
default: |
|
broadphase = new Ammo.btDbvtBroadphase; |
|
break; |
|
} |
|
|
|
world = new Ammo.btDiscreteDynamicsWorld( dispatcher, broadphase, solver, collisionConfiguration ); |
|
|
|
fixedTimeStep = params.fixedTimeStep; |
|
rateLimit = params.rateLimit; |
|
|
|
transferableMessage({ cmd: 'worldReady' }); |
|
}; |
|
|
|
public_functions.registerMaterial = function( description ) { |
|
_materials[ description.id ] = description; |
|
}; |
|
|
|
public_functions.unRegisterMaterial = function( description ) { |
|
delete _materials[ description.id ]; |
|
}; |
|
|
|
public_functions.setFixedTimeStep = function( description ) { |
|
fixedTimeStep = description; |
|
}; |
|
|
|
public_functions.setGravity = function( description ) { |
|
_vec3_1.setX(description.x); |
|
_vec3_1.setY(description.y); |
|
_vec3_1.setZ(description.z); |
|
world.setGravity(_vec3_1); |
|
}; |
|
|
|
public_functions.addObject = function( description ) { |
|
|
|
var i, |
|
localInertia, shape, motionState, rbInfo, body; |
|
|
|
shape = createShape( description ); |
|
if (!shape) return |
|
// If there are children then this is a compound shape |
|
if ( description.children ) { |
|
var compound_shape = new Ammo.btCompoundShape, _child; |
|
compound_shape.addChildShape( _transform, shape ); |
|
|
|
for ( i = 0; i < description.children.length; i++ ) { |
|
_child = description.children[i]; |
|
|
|
var trans = new Ammo.btTransform; |
|
trans.setIdentity(); |
|
|
|
_vec3_1.setX(_child.position_offset.x); |
|
_vec3_1.setY(_child.position_offset.y); |
|
_vec3_1.setZ(_child.position_offset.z); |
|
trans.setOrigin(_vec3_1); |
|
|
|
_quat.setX(_child.rotation.x); |
|
_quat.setY(_child.rotation.y); |
|
_quat.setZ(_child.rotation.z); |
|
_quat.setW(_child.rotation.w); |
|
trans.setRotation(_quat); |
|
|
|
shape = createShape( description.children[i] ); |
|
compound_shape.addChildShape( trans, shape ); |
|
Ammo.destroy(trans); |
|
} |
|
|
|
shape = compound_shape; |
|
_compound_shapes[ description.id ] = shape; |
|
} |
|
_vec3_1.setX(0); |
|
_vec3_1.setY(0); |
|
_vec3_1.setZ(0); |
|
shape.calculateLocalInertia( description.mass, _vec3_1 ); |
|
|
|
_transform.setIdentity(); |
|
|
|
_vec3_2.setX(description.position.x); |
|
_vec3_2.setY(description.position.y); |
|
_vec3_2.setZ(description.position.z); |
|
_transform.setOrigin(_vec3_2); |
|
|
|
_quat.setX(description.rotation.x); |
|
_quat.setY(description.rotation.y); |
|
_quat.setZ(description.rotation.z); |
|
_quat.setW(description.rotation.w); |
|
_transform.setRotation(_quat); |
|
|
|
motionState = new Ammo.btDefaultMotionState( _transform ); // #TODO: btDefaultMotionState supports center of mass offset as second argument - implement |
|
rbInfo = new Ammo.btRigidBodyConstructionInfo( description.mass, motionState, shape, _vec3_1 ); |
|
|
|
if ( description.materialId !== undefined ) { |
|
rbInfo.set_m_friction( _materials[ description.materialId ].friction ); |
|
rbInfo.set_m_restitution( _materials[ description.materialId ].restitution ); |
|
} |
|
|
|
body = new Ammo.btRigidBody( rbInfo ); |
|
Ammo.destroy(rbInfo); |
|
|
|
if ( typeof description.collision_flags !== 'undefined' ) { |
|
body.setCollisionFlags( description.collision_flags ); |
|
} |
|
|
|
world.addRigidBody( body ); |
|
|
|
body.id = description.id; |
|
_objects[ body.id ] = body; |
|
_motion_states[ body.id ] = motionState; |
|
|
|
var ptr = body.a != undefined ? body.a : body.ptr; |
|
_objects_ammo[ptr] = body.id; |
|
_num_objects++; |
|
|
|
transferableMessage({ cmd: 'objectReady', params: body.id }); |
|
}; |
|
|
|
public_functions.addVehicle = function( description ) { |
|
var vehicle_tuning = new Ammo.btVehicleTuning(), |
|
vehicle; |
|
|
|
vehicle_tuning.set_m_suspensionStiffness( description.suspension_stiffness ); |
|
vehicle_tuning.set_m_suspensionCompression( description.suspension_compression ); |
|
vehicle_tuning.set_m_suspensionDamping( description.suspension_damping ); |
|
vehicle_tuning.set_m_maxSuspensionTravelCm( description.max_suspension_travel ); |
|
vehicle_tuning.set_m_maxSuspensionForce( description.max_suspension_force ); |
|
|
|
vehicle = new Ammo.btRaycastVehicle( vehicle_tuning, _objects[ description.rigidBody ], new Ammo.btDefaultVehicleRaycaster( world ) ); |
|
vehicle.tuning = vehicle_tuning; |
|
|
|
_objects[ description.rigidBody ].setActivationState( 4 ); |
|
vehicle.setCoordinateSystem( 0, 1, 2 ); |
|
|
|
world.addVehicle( vehicle ); |
|
_vehicles[ description.id ] = vehicle; |
|
}; |
|
public_functions.removeVehicle = function( description ) { |
|
delete _vehicles[ description.id ]; |
|
}; |
|
|
|
public_functions.addWheel = function( description ) { |
|
if ( _vehicles[description.id] !== undefined ) { |
|
var tuning = _vehicles[description.id].tuning; |
|
if ( description.tuning !== undefined ) { |
|
tuning = new Ammo.btVehicleTuning(); |
|
tuning.set_m_suspensionStiffness( description.tuning.suspension_stiffness ); |
|
tuning.set_m_suspensionCompression( description.tuning.suspension_compression ); |
|
tuning.set_m_suspensionDamping( description.tuning.suspension_damping ); |
|
tuning.set_m_maxSuspensionTravelCm( description.tuning.max_suspension_travel ); |
|
tuning.set_m_maxSuspensionForce( description.tuning.max_suspension_force ); |
|
} |
|
|
|
_vec3_1.setX(description.connection_point.x); |
|
_vec3_1.setY(description.connection_point.y); |
|
_vec3_1.setZ(description.connection_point.z); |
|
|
|
_vec3_2.setX(description.wheel_direction.x); |
|
_vec3_2.setY(description.wheel_direction.y); |
|
_vec3_2.setZ(description.wheel_direction.z); |
|
|
|
_vec3_3.setX(description.wheel_axle.x); |
|
_vec3_3.setY(description.wheel_axle.y); |
|
_vec3_3.setZ(description.wheel_axle.z); |
|
|
|
_vehicles[description.id].addWheel( |
|
_vec3_1, |
|
_vec3_2, |
|
_vec3_3, |
|
description.suspension_rest_length, |
|
description.wheel_radius, |
|
tuning, |
|
description.is_front_wheel |
|
); |
|
} |
|
|
|
_num_wheels++; |
|
|
|
if ( SUPPORT_TRANSFERABLE ) { |
|
vehiclereport = new Float32Array(1 + _num_wheels * VEHICLEREPORT_ITEMSIZE); // message id & ( # of objects to report * # of values per object ) |
|
vehiclereport[0] = MESSAGE_TYPES.VEHICLEREPORT; |
|
} else { |
|
vehiclereport = [ MESSAGE_TYPES.VEHICLEREPORT ]; |
|
} |
|
}; |
|
|
|
public_functions.setSteering = function( details ) { |
|
if ( _vehicles[details.id] !== undefined ) { |
|
_vehicles[details.id].setSteeringValue( details.steering, details.wheel ); |
|
} |
|
}; |
|
public_functions.setBrake = function( details ) { |
|
if ( _vehicles[details.id] !== undefined ) { |
|
_vehicles[details.id].setBrake( details.brake, details.wheel ); |
|
} |
|
}; |
|
public_functions.applyEngineForce = function( details ) { |
|
if ( _vehicles[details.id] !== undefined ) { |
|
_vehicles[details.id].applyEngineForce( details.force, details.wheel ); |
|
} |
|
}; |
|
|
|
public_functions.removeObject = function( details ) { |
|
world.removeRigidBody( _objects[details.id] ); |
|
Ammo.destroy(_objects[details.id]); |
|
Ammo.destroy(_motion_states[details.id]); |
|
if (_compound_shapes[details.id]) Ammo.destroy(_compound_shapes[details.id]); |
|
if (_noncached_shapes[details.id]) Ammo.destroy(_noncached_shapes[details.id]); |
|
var ptr = _objects[details.id].a != undefined ? _objects[details.id].a : _objects[details.id].ptr; |
|
delete _objects_ammo[ptr]; |
|
delete _objects[details.id]; |
|
delete _motion_states[details.id]; |
|
if (_compound_shapes[details.id]) delete _compound_shapes[details.id]; |
|
if (_noncached_shapes[details.id]) delete _noncached_shapes[details.id]; |
|
_num_objects--; |
|
}; |
|
|
|
public_functions.updateTransform = function( details ) { |
|
_object = _objects[details.id]; |
|
_object.getMotionState().getWorldTransform( _transform ); |
|
|
|
if ( details.pos ) { |
|
_vec3_1.setX(details.pos.x); |
|
_vec3_1.setY(details.pos.y); |
|
_vec3_1.setZ(details.pos.z); |
|
_transform.setOrigin(_vec3_1); |
|
} |
|
|
|
if ( details.quat ) { |
|
_quat.setX(details.quat.x); |
|
_quat.setY(details.quat.y); |
|
_quat.setZ(details.quat.z); |
|
_quat.setW(details.quat.w); |
|
_transform.setRotation(_quat); |
|
} |
|
|
|
_object.setWorldTransform( _transform ); |
|
_object.activate(); |
|
}; |
|
|
|
public_functions.updateMass = function( details ) { |
|
// #TODO: changing a static object into dynamic is buggy |
|
_object = _objects[details.id]; |
|
|
|
// Per http://www.bulletphysics.org/Bullet/phpBB3/viewtopic.php?p=&f=9&t=3663#p13816 |
|
world.removeRigidBody( _object ); |
|
|
|
_vec3_1.setX(0); |
|
_vec3_1.setY(0); |
|
_vec3_1.setZ(0); |
|
|
|
_object.setMassProps( details.mass, _vec3_1 ); |
|
world.addRigidBody( _object ); |
|
_object.activate(); |
|
}; |
|
|
|
public_functions.applyCentralImpulse = function ( details ) { |
|
|
|
_vec3_1.setX(details.x); |
|
_vec3_1.setY(details.y); |
|
_vec3_1.setZ(details.z); |
|
|
|
_objects[details.id].applyCentralImpulse(_vec3_1); |
|
_objects[details.id].activate(); |
|
}; |
|
|
|
public_functions.applyImpulse = function ( details ) { |
|
|
|
_vec3_1.setX(details.impulse_x); |
|
_vec3_1.setY(details.impulse_y); |
|
_vec3_1.setZ(details.impulse_z); |
|
|
|
_vec3_2.setX(details.x); |
|
_vec3_2.setY(details.y); |
|
_vec3_2.setZ(details.z); |
|
|
|
_objects[details.id].applyImpulse( |
|
_vec3_1, |
|
_vec3_2 |
|
); |
|
_objects[details.id].activate(); |
|
}; |
|
|
|
public_functions.applyCentralForce = function ( details ) { |
|
|
|
_vec3_1.setX(details.x); |
|
_vec3_1.setY(details.y); |
|
_vec3_1.setZ(details.z); |
|
|
|
_objects[details.id].applyCentralForce(_vec3_1); |
|
_objects[details.id].activate(); |
|
}; |
|
|
|
public_functions.applyForce = function ( details ) { |
|
|
|
_vec3_1.setX(details.impulse_x); |
|
_vec3_1.setY(details.impulse_y); |
|
_vec3_1.setZ(details.impulse_z); |
|
|
|
_vec3_2.setX(details.x); |
|
_vec3_2.setY(details.y); |
|
_vec3_2.setZ(details.z); |
|
|
|
_objects[details.id].applyForce( |
|
_vec3_1, |
|
_vec3_2 |
|
); |
|
_objects[details.id].activate(); |
|
}; |
|
|
|
public_functions.setAngularVelocity = function ( details ) { |
|
|
|
_vec3_1.setX(details.x); |
|
_vec3_1.setY(details.y); |
|
_vec3_1.setZ(details.z); |
|
|
|
_objects[details.id].setAngularVelocity( |
|
_vec3_1 |
|
); |
|
_objects[details.id].activate(); |
|
}; |
|
|
|
public_functions.setLinearVelocity = function ( details ) { |
|
|
|
_vec3_1.setX(details.x); |
|
_vec3_1.setY(details.y); |
|
_vec3_1.setZ(details.z); |
|
|
|
_objects[details.id].setLinearVelocity( |
|
_vec3_1 |
|
); |
|
_objects[details.id].activate(); |
|
}; |
|
|
|
public_functions.setAngularFactor = function ( details ) { |
|
|
|
_vec3_1.setX(details.x); |
|
_vec3_1.setY(details.y); |
|
_vec3_1.setZ(details.z); |
|
|
|
_objects[details.id].setAngularFactor( |
|
_vec3_1 |
|
); |
|
}; |
|
|
|
public_functions.setLinearFactor = function ( details ) { |
|
|
|
_vec3_1.setX(details.x); |
|
_vec3_1.setY(details.y); |
|
_vec3_1.setZ(details.z); |
|
|
|
_objects[details.id].setLinearFactor( |
|
_vec3_1 |
|
); |
|
}; |
|
|
|
public_functions.setDamping = function ( details ) { |
|
_objects[details.id].setDamping( details.linear, details.angular ); |
|
}; |
|
|
|
public_functions.setCcdMotionThreshold = function ( details ) { |
|
_objects[details.id].setCcdMotionThreshold( details.threshold ); |
|
}; |
|
|
|
public_functions.setCcdSweptSphereRadius = function ( details ) { |
|
_objects[details.id].setCcdSweptSphereRadius( details.radius ); |
|
}; |
|
|
|
public_functions.addConstraint = function ( details ) { |
|
var constraint; |
|
|
|
switch ( details.type ) { |
|
|
|
case 'point': |
|
if ( details.objectb === undefined ) { |
|
|
|
_vec3_1.setX(details.positiona.x); |
|
_vec3_1.setY(details.positiona.y); |
|
_vec3_1.setZ(details.positiona.z); |
|
|
|
constraint = new Ammo.btPoint2PointConstraint( |
|
_objects[ details.objecta ], |
|
_vec3_1 |
|
); |
|
} else { |
|
|
|
_vec3_1.setX(details.positiona.x); |
|
_vec3_1.setY(details.positiona.y); |
|
_vec3_1.setZ(details.positiona.z); |
|
|
|
_vec3_2.setX(details.positionb.x); |
|
_vec3_2.setY(details.positionb.y); |
|
_vec3_2.setZ(details.positionb.z); |
|
|
|
constraint = new Ammo.btPoint2PointConstraint( |
|
_objects[ details.objecta ], |
|
_objects[ details.objectb ], |
|
_vec3_1, |
|
_vec3_2 |
|
); |
|
} |
|
break; |
|
|
|
case 'hinge': |
|
if ( details.objectb === undefined ) { |
|
|
|
_vec3_1.setX(details.positiona.x); |
|
_vec3_1.setY(details.positiona.y); |
|
_vec3_1.setZ(details.positiona.z); |
|
|
|
_vec3_2.setX(details.axis.x); |
|
_vec3_2.setY(details.axis.y); |
|
_vec3_2.setZ(details.axis.z); |
|
|
|
constraint = new Ammo.btHingeConstraint( |
|
_objects[ details.objecta ], |
|
_vec3_1, |
|
_vec3_2 |
|
); |
|
} else { |
|
|
|
_vec3_1.setX(details.positiona.x); |
|
_vec3_1.setY(details.positiona.y); |
|
_vec3_1.setZ(details.positiona.z); |
|
|
|
_vec3_2.setX(details.positionb.x); |
|
_vec3_2.setY(details.positionb.y); |
|
_vec3_2.setZ(details.positionb.z); |
|
|
|
_vec3_3.setX(details.axis.x); |
|
_vec3_3.setY(details.axis.y); |
|
_vec3_3.setZ(details.axis.z); |
|
|
|
constraint = new Ammo.btHingeConstraint( |
|
_objects[ details.objecta ], |
|
_objects[ details.objectb ], |
|
_vec3_1, |
|
_vec3_2, |
|
_vec3_3, |
|
_vec3_3 |
|
); |
|
} |
|
break; |
|
|
|
case 'slider': |
|
var transforma, transformb, rotation; |
|
|
|
transforma = new Ammo.btTransform(); |
|
|
|
_vec3_1.setX(details.positiona.x); |
|
_vec3_1.setY(details.positiona.y); |
|
_vec3_1.setZ(details.positiona.z); |
|
|
|
transforma.setOrigin(_vec3_1); |
|
|
|
var rotation = transforma.getRotation(); |
|
rotation.setEuler( details.axis.x, details.axis.y, details.axis.z ); |
|
transforma.setRotation( rotation ); |
|
|
|
if ( details.objectb ) { |
|
transformb = new Ammo.btTransform(); |
|
|
|
_vec3_2.setX(details.positionb.x); |
|
_vec3_2.setY(details.positionb.y); |
|
_vec3_2.setZ(details.positionb.z); |
|
|
|
transformb.setOrigin(_vec3_2); |
|
|
|
rotation = transformb.getRotation(); |
|
rotation.setEuler( details.axis.x, details.axis.y, details.axis.z ); |
|
transformb.setRotation( rotation ); |
|
|
|
constraint = new Ammo.btSliderConstraint( |
|
_objects[ details.objecta ], |
|
_objects[ details.objectb ], |
|
transforma, |
|
transformb, |
|
true |
|
); |
|
} else { |
|
constraint = new Ammo.btSliderConstraint( |
|
_objects[ details.objecta ], |
|
transforma, |
|
true |
|
); |
|
} |
|
|
|
Ammo.destroy(transforma); |
|
if (transformb != undefined) { |
|
Ammo.destroy(transformb); |
|
} |
|
break; |
|
|
|
case 'conetwist': |
|
var transforma, transformb; |
|
|
|
transforma = new Ammo.btTransform(); |
|
transforma.setIdentity(); |
|
|
|
transformb = new Ammo.btTransform(); |
|
transformb.setIdentity(); |
|
|
|
_vec3_1.setX(details.positiona.x); |
|
_vec3_1.setY(details.positiona.y); |
|
_vec3_1.setZ(details.positiona.z); |
|
|
|
_vec3_2.setX(details.positionb.x); |
|
_vec3_2.setY(details.positionb.y); |
|
_vec3_2.setZ(details.positionb.z); |
|
|
|
transforma.setOrigin(_vec3_1); |
|
transformb.setOrigin(_vec3_2); |
|
|
|
var rotation = transforma.getRotation(); |
|
rotation.setEulerZYX( -details.axisa.z, -details.axisa.y, -details.axisa.x ); |
|
transforma.setRotation( rotation ); |
|
|
|
rotation = transformb.getRotation(); |
|
rotation.setEulerZYX( -details.axisb.z, -details.axisb.y, -details.axisb.x ); |
|
transformb.setRotation( rotation ); |
|
|
|
constraint = new Ammo.btConeTwistConstraint( |
|
_objects[ details.objecta ], |
|
_objects[ details.objectb ], |
|
transforma, |
|
transformb |
|
); |
|
|
|
constraint.setLimit( Math.PI, 0, Math.PI ); |
|
|
|
Ammo.destroy(transforma); |
|
Ammo.destroy(transformb); |
|
|
|
break; |
|
|
|
case 'dof': |
|
var transforma, transformb, rotation; |
|
|
|
transforma = new Ammo.btTransform(); |
|
transforma.setIdentity(); |
|
|
|
_vec3_1.setX(details.positiona.x); |
|
_vec3_1.setY(details.positiona.y); |
|
_vec3_1.setZ(details.positiona.z); |
|
|
|
transforma.setOrigin(_vec3_1 ); |
|
|
|
rotation = transforma.getRotation(); |
|
rotation.setEulerZYX( -details.axisa.z, -details.axisa.y, -details.axisa.x ); |
|
transforma.setRotation( rotation ); |
|
|
|
if ( details.objectb ) { |
|
transformb = new Ammo.btTransform(); |
|
transformb.setIdentity(); |
|
|
|
_vec3_2.setX(details.positionb.x); |
|
_vec3_2.setY(details.positionb.y); |
|
_vec3_2.setZ(details.positionb.z); |
|
|
|
transformb.setOrigin(_vec3_2); |
|
|
|
rotation = transformb.getRotation(); |
|
rotation.setEulerZYX( -details.axisb.z, -details.axisb.y, -details.axisb.x ); |
|
transformb.setRotation( rotation ); |
|
|
|
constraint = new Ammo.btGeneric6DofConstraint( |
|
_objects[ details.objecta ], |
|
_objects[ details.objectb ], |
|
transforma, |
|
transformb |
|
); |
|
} else { |
|
constraint = new Ammo.btGeneric6DofConstraint( |
|
_objects[ details.objecta ], |
|
transforma |
|
); |
|
} |
|
Ammo.destroy(transforma); |
|
if (transformb != undefined) { |
|
Ammo.destroy(transformb); |
|
} |
|
break; |
|
|
|
default: |
|
return; |
|
|
|
}; |
|
|
|
world.addConstraint( constraint ); |
|
|
|
constraint.enableFeedback(); |
|
_constraints[ details.id ] = constraint; |
|
_num_constraints++; |
|
|
|
if ( SUPPORT_TRANSFERABLE ) { |
|
constraintreport = new Float32Array(1 + _num_constraints * CONSTRAINTREPORT_ITEMSIZE); // message id & ( # of objects to report * # of values per object ) |
|
constraintreport[0] = MESSAGE_TYPES.CONSTRAINTREPORT; |
|
} else { |
|
constraintreport = [ MESSAGE_TYPES.CONSTRAINTREPORT ]; |
|
} |
|
}; |
|
|
|
public_functions.removeConstraint = function( details ) { |
|
var constraint = _constraints[ details.id ]; |
|
if ( constraint !== undefined ) { |
|
world.removeConstraint( constraint ); |
|
delete _constraints[ details.id ]; |
|
_num_constraints--; |
|
} |
|
}; |
|
|
|
public_functions.constraint_setBreakingImpulseThreshold = function( details ) { |
|
var constraint = _constraints[ details.id ]; |
|
if ( constraint !== undefind ) { |
|
constraint.setBreakingImpulseThreshold( details.threshold ); |
|
} |
|
}; |
|
|
|
public_functions.simulate = function simulate( params ) { |
|
if ( world ) { |
|
params = params || {}; |
|
|
|
if ( !params.timeStep ) { |
|
if ( last_simulation_time ) { |
|
params.timeStep = 0; |
|
while ( params.timeStep + last_simulation_duration <= fixedTimeStep ) { |
|
params.timeStep = ( Date.now() - last_simulation_time ) / 1000; // time since last simulation |
|
} |
|
} else { |
|
params.timeStep = fixedTimeStep; // handle first frame |
|
} |
|
} else { |
|
if ( params.timeStep < fixedTimeStep ) { |
|
params.timeStep = fixedTimeStep; |
|
} |
|
} |
|
|
|
params.maxSubSteps = params.maxSubSteps || Math.ceil( params.timeStep / fixedTimeStep ); // If maxSubSteps is not defined, keep the simulation fully up to date |
|
|
|
last_simulation_duration = Date.now(); |
|
world.stepSimulation( params.timeStep, params.maxSubSteps, fixedTimeStep ); |
|
|
|
reportVehicles(); |
|
reportCollisions(); |
|
reportConstraints(); |
|
reportWorld(); |
|
|
|
last_simulation_duration = ( Date.now() - last_simulation_duration ) / 1000; |
|
last_simulation_time = Date.now(); |
|
} |
|
}; |
|
|
|
|
|
// Constraint functions |
|
public_functions.hinge_setLimits = function( params ) { |
|
_constraints[ params.constraint ].setLimit( params.low, params.high, 0, params.bias_factor, params.relaxation_factor ); |
|
}; |
|
public_functions.hinge_enableAngularMotor = function( params ) { |
|
var constraint = _constraints[ params.constraint ]; |
|
constraint.enableAngularMotor( true, params.velocity, params.acceleration ); |
|
constraint.getRigidBodyA().activate(); |
|
if ( constraint.getRigidBodyB() ) { |
|
constraint.getRigidBodyB().activate(); |
|
} |
|
}; |
|
public_functions.hinge_disableMotor = function( params ) { |
|
_constraints[ params.constraint ].enableMotor( false ); |
|
if ( constraint.getRigidBodyB() ) { |
|
constraint.getRigidBodyB().activate(); |
|
} |
|
}; |
|
|
|
public_functions.slider_setLimits = function( params ) { |
|
var constraint = _constraints[ params.constraint ]; |
|
constraint.setLowerLinLimit( params.lin_lower || 0 ); |
|
constraint.setUpperLinLimit( params.lin_upper || 0 ); |
|
|
|
constraint.setLowerAngLimit( params.ang_lower || 0 ); |
|
constraint.setUpperAngLimit( params.ang_upper || 0 ); |
|
}; |
|
public_functions.slider_setRestitution = function( params ) { |
|
var constraint = _constraints[ params.constraint ]; |
|
constraint.setSoftnessLimLin( params.linear || 0 ); |
|
constraint.setSoftnessLimAng( params.angular || 0 ); |
|
}; |
|
public_functions.slider_enableLinearMotor = function( params ) { |
|
var constraint = _constraints[ params.constraint ]; |
|
constraint.setTargetLinMotorVelocity( params.velocity ); |
|
constraint.setMaxLinMotorForce( params.acceleration ); |
|
constraint.setPoweredLinMotor( true ); |
|
constraint.getRigidBodyA().activate(); |
|
if ( constraint.getRigidBodyB ) { |
|
constraint.getRigidBodyB().activate(); |
|
} |
|
}; |
|
public_functions.slider_disableLinearMotor = function( params ) { |
|
var constraint = _constraints[ params.constraint ]; |
|
constraint.setPoweredLinMotor( false ); |
|
if ( constraint.getRigidBodyB() ) { |
|
constraint.getRigidBodyB().activate(); |
|
} |
|
}; |
|
public_functions.slider_enableAngularMotor = function( params ) { |
|
var constraint = _constraints[ params.constraint ]; |
|
constraint.setTargetAngMotorVelocity( params.velocity ); |
|
constraint.setMaxAngMotorForce( params.acceleration ); |
|
constraint.setPoweredAngMotor( true ); |
|
constraint.getRigidBodyA().activate(); |
|
if ( constraint.getRigidBodyB() ) { |
|
constraint.getRigidBodyB().activate(); |
|
} |
|
}; |
|
public_functions.slider_disableAngularMotor = function( params ) { |
|
var constraint = _constraints[ params.constraint ]; |
|
constraint.setPoweredAngMotor( false ); |
|
constraint.getRigidBodyA().activate(); |
|
if ( constraint.getRigidBodyB() ) { |
|
constraint.getRigidBodyB().activate(); |
|
} |
|
}; |
|
|
|
public_functions.conetwist_setLimit = function( params ) { |
|
_constraints[ params.constraint ].setLimit( params.z, params.y, params.x ); // ZYX order |
|
}; |
|
public_functions.conetwist_enableMotor = function( params ) { |
|
var constraint = _constraints[ params.constraint ]; |
|
constraint.enableMotor( true ); |
|
constraint.getRigidBodyA().activate(); |
|
constraint.getRigidBodyB().activate(); |
|
}; |
|
public_functions.conetwist_setMaxMotorImpulse = function( params ) { |
|
var constraint = _constraints[ params.constraint ]; |
|
constraint.setMaxMotorImpulse( params.max_impulse ); |
|
constraint.getRigidBodyA().activate(); |
|
constraint.getRigidBodyB().activate(); |
|
}; |
|
public_functions.conetwist_setMotorTarget = function( params ) { |
|
var constraint = _constraints[ params.constraint ]; |
|
|
|
_quat.setX(params.x); |
|
_quat.setY(params.y); |
|
_quat.setZ(params.z); |
|
_quat.setW(params.w); |
|
|
|
constraint.setMotorTarget(_quat); |
|
|
|
constraint.getRigidBodyA().activate(); |
|
constraint.getRigidBodyB().activate(); |
|
}; |
|
public_functions.conetwist_disableMotor = function( params ) { |
|
var constraint = _constraints[ params.constraint ]; |
|
constraint.enableMotor( false ); |
|
constraint.getRigidBodyA().activate(); |
|
constraint.getRigidBodyB().activate(); |
|
}; |
|
|
|
public_functions.dof_setLinearLowerLimit = function( params ) { |
|
var constraint = _constraints[ params.constraint ]; |
|
|
|
_vec3_1.setX(params.x); |
|
_vec3_1.setY(params.y); |
|
_vec3_1.setZ(params.z); |
|
|
|
constraint.setLinearLowerLimit(_vec3_1); |
|
|
|
constraint.getRigidBodyA().activate(); |
|
if ( constraint.getRigidBodyB() ) { |
|
constraint.getRigidBodyB().activate(); |
|
} |
|
}; |
|
public_functions.dof_setLinearUpperLimit = function( params ) { |
|
var constraint = _constraints[ params.constraint ]; |
|
|
|
_vec3_1.setX(params.x); |
|
_vec3_1.setY(params.y); |
|
_vec3_1.setZ(params.z); |
|
|
|
constraint.setLinearUpperLimit(_vec3_1); |
|
|
|
constraint.getRigidBodyA().activate(); |
|
if ( constraint.getRigidBodyB() ) { |
|
constraint.getRigidBodyB().activate(); |
|
} |
|
}; |
|
public_functions.dof_setAngularLowerLimit = function( params ) { |
|
var constraint = _constraints[ params.constraint ]; |
|
|
|
_vec3_1.setX(params.x); |
|
_vec3_1.setY(params.y); |
|
_vec3_1.setZ(params.z); |
|
|
|
constraint.setAngularLowerLimit(_vec3_1); |
|
|
|
constraint.getRigidBodyA().activate(); |
|
if ( constraint.getRigidBodyB() ) { |
|
constraint.getRigidBodyB().activate(); |
|
} |
|
}; |
|
public_functions.dof_setAngularUpperLimit = function( params ) { |
|
var constraint = _constraints[ params.constraint ]; |
|
|
|
_vec3_1.setX(params.x); |
|
_vec3_1.setY(params.y); |
|
_vec3_1.setZ(params.z); |
|
|
|
constraint.setAngularUpperLimit(_vec3_1); |
|
|
|
constraint.getRigidBodyA().activate(); |
|
if ( constraint.getRigidBodyB() ) { |
|
constraint.getRigidBodyB().activate(); |
|
} |
|
}; |
|
public_functions.dof_enableAngularMotor = function( params ) { |
|
var constraint = _constraints[ params.constraint ]; |
|
|
|
var motor = constraint.getRotationalLimitMotor( params.which ); |
|
motor.set_m_enableMotor( true ); |
|
|
|
constraint.getRigidBodyA().activate(); |
|
if ( constraint.getRigidBodyB() ) { |
|
constraint.getRigidBodyB().activate(); |
|
} |
|
}; |
|
public_functions.dof_configureAngularMotor = function( params ) { |
|
var constraint = _constraints[ params.constraint ]; |
|
|
|
var motor = constraint.getRotationalLimitMotor( params.which ); |
|
|
|
motor.set_m_loLimit( params.low_angle ); |
|
motor.set_m_hiLimit( params.high_angle ); |
|
motor.set_m_targetVelocity( params.velocity ); |
|
motor.set_m_maxMotorForce( params.max_force ); |
|
|
|
constraint.getRigidBodyA().activate(); |
|
if ( constraint.getRigidBodyB() ) { |
|
constraint.getRigidBodyB().activate(); |
|
} |
|
}; |
|
public_functions.dof_disableAngularMotor = function( params ) { |
|
var constraint = _constraints[ params.constraint ]; |
|
|
|
var motor = constraint.getRotationalLimitMotor( params.which ); |
|
motor.set_m_enableMotor( false ); |
|
|
|
constraint.getRigidBodyA().activate(); |
|
if ( constraint.getRigidBodyB() ) { |
|
constraint.getRigidBodyB().activate(); |
|
} |
|
}; |
|
|
|
reportWorld = function() { |
|
var index, object, |
|
transform, origin, rotation, |
|
offset = 0, |
|
i = 0; |
|
|
|
if ( SUPPORT_TRANSFERABLE ) { |
|
if ( worldreport.length < 2 + _num_objects * WORLDREPORT_ITEMSIZE ) { |
|
worldreport = new Float32Array( |
|
2 + // message id & # objects in report |
|
( Math.ceil( _num_objects / REPORT_CHUNKSIZE ) * REPORT_CHUNKSIZE ) * WORLDREPORT_ITEMSIZE // # of values needed * item size |
|
); |
|
worldreport[0] = MESSAGE_TYPES.WORLDREPORT; |
|
} |
|
} |
|
|
|
worldreport[1] = _num_objects; // record how many objects we're reporting on |
|
|
|
//for ( i = 0; i < worldreport[1]; i++ ) { |
|
for ( index in _objects ) { |
|
if ( _objects.hasOwnProperty( index ) ) { |
|
object = _objects[index]; |
|
|
|
// #TODO: we can't use center of mass transform when center of mass can change, |
|
// but getMotionState().getWorldTransform() screws up on objects that have been moved |
|
//object.getMotionState().getWorldTransform( transform ); |
|
transform = object.getCenterOfMassTransform(); |
|
|
|
origin = transform.getOrigin(); |
|
rotation = transform.getRotation(); |
|
|
|
// add values to report |
|
offset = 2 + (i++) * WORLDREPORT_ITEMSIZE; |
|
|
|
worldreport[ offset ] = object.id; |
|
|
|
worldreport[ offset + 1 ] = origin.x(); |
|
worldreport[ offset + 2 ] = origin.y(); |
|
worldreport[ offset + 3 ] = origin.z(); |
|
|
|
worldreport[ offset + 4 ] = rotation.x(); |
|
worldreport[ offset + 5 ] = rotation.y(); |
|
worldreport[ offset + 6 ] = rotation.z(); |
|
worldreport[ offset + 7 ] = rotation.w(); |
|
|
|
_vector = object.getLinearVelocity(); |
|
worldreport[ offset + 8 ] = _vector.x(); |
|
worldreport[ offset + 9 ] = _vector.y(); |
|
worldreport[ offset + 10 ] = _vector.z(); |
|
|
|
_vector = object.getAngularVelocity(); |
|
worldreport[ offset + 11 ] = _vector.x(); |
|
worldreport[ offset + 12 ] = _vector.y(); |
|
worldreport[ offset + 13 ] = _vector.z(); |
|
} |
|
} |
|
|
|
|
|
if ( SUPPORT_TRANSFERABLE ) { |
|
transferableMessage( worldreport.buffer, [worldreport.buffer] ); |
|
} else { |
|
transferableMessage( worldreport ); |
|
} |
|
|
|
}; |
|
|
|
reportCollisions = function() { |
|
var i, offset, |
|
dp = world.getDispatcher(), |
|
num = dp.getNumManifolds(), |
|
manifold, num_contacts, j, pt, |
|
_collided = false; |
|
|
|
if ( SUPPORT_TRANSFERABLE ) { |
|
if ( collisionreport.length < 2 + num * COLLISIONREPORT_ITEMSIZE ) { |
|
collisionreport = new Float32Array( |
|
2 + // message id & # objects in report |
|
( Math.ceil( _num_objects / REPORT_CHUNKSIZE ) * REPORT_CHUNKSIZE ) * COLLISIONREPORT_ITEMSIZE // # of values needed * item size |
|
); |
|
collisionreport[0] = MESSAGE_TYPES.COLLISIONREPORT; |
|
} |
|
} |
|
|
|
collisionreport[1] = 0; // how many collisions we're reporting on |
|
|
|
for ( i = 0; i < num; i++ ) { |
|
manifold = dp.getManifoldByIndexInternal( i ); |
|
|
|
num_contacts = manifold.getNumContacts(); |
|
if ( num_contacts === 0 ) { |
|
continue; |
|
} |
|
|
|
for ( j = 0; j < num_contacts; j++ ) { |
|
pt = manifold.getContactPoint( j ); |
|
//if ( pt.getDistance() < 0 ) { |
|
offset = 2 + (collisionreport[1]++) * COLLISIONREPORT_ITEMSIZE; |
|
collisionreport[ offset ] = _objects_ammo[ manifold.getBody0() ]; |
|
collisionreport[ offset + 1 ] = _objects_ammo[ manifold.getBody1() ]; |
|
|
|
_vector = pt.get_m_normalWorldOnB(); |
|
collisionreport[ offset + 2 ] = _vector.x(); |
|
collisionreport[ offset + 3 ] = _vector.y(); |
|
collisionreport[ offset + 4 ] = _vector.z(); |
|
break; |
|
//} |
|
|
|
transferableMessage( _objects_ammo ); |
|
|
|
} |
|
} |
|
|
|
|
|
if ( SUPPORT_TRANSFERABLE ) { |
|
transferableMessage( collisionreport.buffer, [collisionreport.buffer] ); |
|
} else { |
|
transferableMessage( collisionreport ); |
|
} |
|
}; |
|
|
|
reportVehicles = function() { |
|
var index, vehicle, |
|
transform, origin, rotation, |
|
offset = 0, |
|
i = 0, j = 0; |
|
|
|
if ( SUPPORT_TRANSFERABLE ) { |
|
if ( vehiclereport.length < 2 + _num_wheels * VEHICLEREPORT_ITEMSIZE ) { |
|
vehiclereport = new Float32Array( |
|
2 + // message id & # objects in report |
|
( Math.ceil( _num_wheels / REPORT_CHUNKSIZE ) * REPORT_CHUNKSIZE ) * VEHICLEREPORT_ITEMSIZE // # of values needed * item size |
|
); |
|
vehiclereport[0] = MESSAGE_TYPES.VEHICLEREPORT; |
|
} |
|
} |
|
|
|
for ( index in _vehicles ) { |
|
if ( _vehicles.hasOwnProperty( index ) ) { |
|
vehicle = _vehicles[index]; |
|
|
|
for ( j = 0; j < vehicle.getNumWheels(); j++ ) { |
|
|
|
//vehicle.updateWheelTransform( j, true ); |
|
|
|
//transform = vehicle.getWheelTransformWS( j ); |
|
transform = vehicle.getWheelInfo( j ).get_m_worldTransform(); |
|
|
|
origin = transform.getOrigin(); |
|
rotation = transform.getRotation(); |
|
|
|
// add values to report |
|
offset = 1 + (i++) * VEHICLEREPORT_ITEMSIZE; |
|
|
|
vehiclereport[ offset ] = index; |
|
vehiclereport[ offset + 1 ] = j; |
|
|
|
vehiclereport[ offset + 2 ] = origin.x(); |
|
vehiclereport[ offset + 3 ] = origin.y(); |
|
vehiclereport[ offset + 4 ] = origin.z(); |
|
|
|
vehiclereport[ offset + 5 ] = rotation.x(); |
|
vehiclereport[ offset + 6 ] = rotation.y(); |
|
vehiclereport[ offset + 7 ] = rotation.z(); |
|
vehiclereport[ offset + 8 ] = rotation.w(); |
|
|
|
} |
|
|
|
} |
|
} |
|
|
|
if ( j !== 0 ) { |
|
if ( SUPPORT_TRANSFERABLE ) { |
|
transferableMessage( vehiclereport.buffer, [vehiclereport.buffer] ); |
|
} else { |
|
transferableMessage( vehiclereport ); |
|
} |
|
} |
|
}; |
|
|
|
reportConstraints = function() { |
|
var index, constraint, |
|
offset_body, |
|
transform, origin, |
|
offset = 0, |
|
i = 0; |
|
|
|
if ( SUPPORT_TRANSFERABLE ) { |
|
if ( constraintreport.length < 2 + _num_constraints * CONSTRAINTREPORT_ITEMSIZE ) { |
|
constraintreport = new Float32Array( |
|
2 + // message id & # objects in report |
|
( Math.ceil( _num_constraints / REPORT_CHUNKSIZE ) * REPORT_CHUNKSIZE ) * CONSTRAINTREPORT_ITEMSIZE // # of values needed * item size |
|
); |
|
constraintreport[0] = MESSAGE_TYPES.CONSTRAINTREPORT; |
|
} |
|
} |
|
|
|
for ( index in _constraints ) { |
|
if ( _constraints.hasOwnProperty( index ) ) { |
|
constraint = _constraints[index]; |
|
offset_body = constraint.getRigidBodyA(); |
|
transform = constraint.getFrameOffsetA(); |
|
origin = transform.getOrigin(); |
|
|
|
// add values to report |
|
offset = 1 + (i++) * CONSTRAINTREPORT_ITEMSIZE; |
|
|
|
constraintreport[ offset ] = index; |
|
constraintreport[ offset + 1 ] = offset_body.id; |
|
constraintreport[ offset + 2 ] = origin.getX(); |
|
constraintreport[ offset + 3 ] = origin.getY(); |
|
constraintreport[ offset + 4 ] = origin.getZ(); |
|
constraintreport[ offset + 5 ] = constraint.getAppliedImpulse(); |
|
} |
|
} |
|
|
|
|
|
if ( i !== 0 ) { |
|
if ( SUPPORT_TRANSFERABLE ) { |
|
transferableMessage( constraintreport.buffer, [constraintreport.buffer] ); |
|
} else { |
|
transferableMessage( constraintreport ); |
|
} |
|
} |
|
|
|
}; |
|
|
|
self.onmessage = function( event ) { |
|
|
|
if ( event.data instanceof Float32Array ) { |
|
// transferable object |
|
|
|
switch ( event.data[0] ) { |
|
case MESSAGE_TYPES.WORLDREPORT: |
|
worldreport = new Float32Array( event.data ); |
|
break; |
|
|
|
case MESSAGE_TYPES.COLLISIONREPORT: |
|
collisionreport = new Float32Array( event.data ); |
|
break; |
|
|
|
case MESSAGE_TYPES.VEHICLEREPORT: |
|
vehiclereport = new Float32Array( event.data ); |
|
break; |
|
|
|
case MESSAGE_TYPES.CONSTRAINTREPORT: |
|
constraintreport = new Float32Array( event.data ); |
|
break; |
|
} |
|
|
|
return; |
|
} |
|
|
|
if ( event.data.cmd && public_functions[event.data.cmd] ) { |
|
//if ( event.data.params.id !== undefined && _objects[event.data.params.id] === undefined && event.data.cmd !== 'addObject' && event.data.cmd !== 'registerMaterial' ) return; |
|
public_functions[event.data.cmd]( event.data.params ); |
|
} |
|
|
|
}; |
|
|
|
</script> |