BulletSim initial checkin

bulletsim
Robert Adams 2011-06-20 17:14:59 -07:00 committed by Dan Lake
parent 7819b4a794
commit 302d72701d
31 changed files with 9141 additions and 0 deletions

View File

@ -0,0 +1,426 @@
/*
* Copyright (c) Contributors, http://opensimulator.org/
* See CONTRIBUTORS.TXT for a full list of copyright holders.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyrightD
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* * Neither the name of the OpenSimulator Project nor the
* names of its contributors may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
using System;
using System.Collections.Generic;
using System.Reflection;
using log4net;
using OpenMetaverse;
using OpenSim.Framework;
using OpenSim.Region.Physics.Manager;
namespace OpenSim.Region.Physics.BulletSPlugin
{
public class BSCharacter : PhysicsActor
{
private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
private static readonly string LogHeader = "[BULLETS CHAR]";
private BSScene _scene;
private String _avName;
private bool _stopped;
private Vector3 _size;
private Vector3 _scale;
private PrimitiveBaseShape _pbs;
private uint _localID = 0;
private bool _grabbed;
private bool _selected;
private Vector3 _position;
private float _mass = 80f;
public float _density = 60f;
public float CAPSULE_RADIUS = 0.37f;
public float CAPSULE_LENGTH = 2.140599f;
private Vector3 _force;
private Vector3 _velocity;
private Vector3 _torque;
private float _collisionScore;
private Vector3 _acceleration;
private Quaternion _orientation;
private int _physicsActorType;
private bool _isPhysical;
private bool _flying;
private bool _setAlwaysRun;
private bool _throttleUpdates;
private bool _isColliding;
private long _collidingStep;
private bool _collidingGround;
private long _collidingGroundStep;
private bool _collidingObj;
private bool _floatOnWater;
private Vector3 _rotationalVelocity;
private bool _kinematic;
private float _buoyancy;
private int _subscribedEventsMs = 0;
private int _lastCollisionTime = 0;
private Vector3 _PIDTarget;
private bool _usePID;
private float _PIDTau;
private bool _useHoverPID;
private float _PIDHoverHeight;
private PIDHoverType _PIDHoverType;
private float _PIDHoverTao;
public BSCharacter(uint localID, String avName, BSScene parent_scene, Vector3 pos, Vector3 size, bool isFlying)
{
_localID = localID;
_avName = avName;
_scene = parent_scene;
_position = pos;
_size = size;
_orientation = Quaternion.Identity;
_velocity = Vector3.Zero;
_buoyancy = 0f; // characters return a buoyancy of zero
_scale = new Vector3(1f, 1f, 1f);
float AVvolume = (float) (Math.PI*Math.Pow(CAPSULE_RADIUS, 2)*CAPSULE_LENGTH);
_mass = _density*AVvolume;
ShapeData shapeData = new ShapeData();
shapeData.ID = _localID;
shapeData.Type = ShapeData.PhysicsShapeType.SHAPE_AVATAR;
shapeData.Position = _position;
shapeData.Rotation = _orientation;
shapeData.Velocity = _velocity;
shapeData.Scale = _scale;
shapeData.Mass = _mass;
shapeData.Buoyancy = isFlying ? 0f : 1f;
shapeData.Static = ShapeData.numericFalse;
// do actual create at taint time
_scene.TaintedObject(delegate()
{
BulletSimAPI.CreateObject(parent_scene.WorldID, shapeData);
});
return;
}
// called when this character is being destroyed and the resources should be released
public void Destroy()
{
_scene.TaintedObject(delegate()
{
BulletSimAPI.DestroyObject(_scene.WorldID, _localID);
});
}
public override void RequestPhysicsterseUpdate()
{
base.RequestPhysicsterseUpdate();
}
public override bool Stopped {
get { return _stopped; }
}
public override Vector3 Size {
get { return _size; }
set { _size = value;
}
}
public override PrimitiveBaseShape Shape {
set { _pbs = value;
}
}
public override uint LocalID {
set { _localID = value;
}
get { return _localID; }
}
public override bool Grabbed {
set { _grabbed = value;
}
}
public override bool Selected {
set { _selected = value;
}
}
public override void CrossingFailure() { return; }
public override void link(PhysicsActor obj) { return; }
public override void delink() { return; }
public override void LockAngularMotion(Vector3 axis) { return; }
public override Vector3 Position {
get {
// _position = BulletSimAPI.GetObjectPosition(_scene.WorldID, _localID);
return _position;
}
set {
_position = value;
_scene.TaintedObject(delegate()
{
BulletSimAPI.SetObjectTranslation(_scene.WorldID, _localID, _position, _orientation);
});
}
}
public override float Mass {
get {
return _mass;
}
}
public override Vector3 Force {
get { return _force; }
set {
_force = value;
m_log.DebugFormat("{0}: Force = {1}", LogHeader, _force);
_scene.TaintedObject(delegate()
{
BulletSimAPI.SetObjectForce(_scene.WorldID, _localID, _force);
});
}
}
public override int VehicleType {
get { return 0; }
set { return; }
}
public override void VehicleFloatParam(int param, float value) { }
public override void VehicleVectorParam(int param, Vector3 value) {}
public override void VehicleRotationParam(int param, Quaternion rotation) { }
public override void VehicleFlags(int param, bool remove) { }
// Allows the detection of collisions with inherently non-physical prims. see llVolumeDetect for more
public override void SetVolumeDetect(int param) { return; }
public override Vector3 GeometricCenter { get { return Vector3.Zero; } }
public override Vector3 CenterOfMass { get { return Vector3.Zero; } }
public override Vector3 Velocity {
get { return _velocity; }
set {
_velocity = value;
_scene.TaintedObject(delegate()
{
BulletSimAPI.SetObjectVelocity(_scene.WorldID, _localID, _velocity);
});
}
}
public override Vector3 Torque {
get { return _torque; }
set { _torque = value;
}
}
public override float CollisionScore {
get { return _collisionScore; }
set { _collisionScore = value;
}
}
public override Vector3 Acceleration {
get { return _acceleration; }
}
public override Quaternion Orientation {
get { return _orientation; }
set {
_orientation = value;
_scene.TaintedObject(delegate()
{
// _position = BulletSimAPI.GetObjectPosition(_scene.WorldID, _localID);
BulletSimAPI.SetObjectTranslation(_scene.WorldID, _localID, _position, _orientation);
});
}
}
public override int PhysicsActorType {
get { return _physicsActorType; }
set { _physicsActorType = value;
}
}
public override bool IsPhysical {
get { return _isPhysical; }
set { _isPhysical = value;
}
}
public override bool Flying {
get { return _flying; }
set {
_flying = value;
_scene.TaintedObject(delegate()
{
// simulate flying by changing the effect of gravity
BulletSimAPI.SetObjectBuoyancy(_scene.WorldID, LocalID, _flying ? 0f : 1f);
});
}
}
public override bool
SetAlwaysRun {
get { return _setAlwaysRun; }
set { _setAlwaysRun = value; }
}
public override bool ThrottleUpdates {
get { return _throttleUpdates; }
set { _throttleUpdates = value; }
}
public override bool IsColliding {
get { return (_collidingStep == _scene.SimulationStep); }
set { _isColliding = value; }
}
public override bool CollidingGround {
get { return (_collidingGroundStep == _scene.SimulationStep); }
set { _collidingGround = value; }
}
public override bool CollidingObj {
get { return _collidingObj; }
set { _collidingObj = value; }
}
public override bool FloatOnWater {
set { _floatOnWater = value; }
}
public override Vector3 RotationalVelocity {
get { return _rotationalVelocity; }
set { _rotationalVelocity = value; }
}
public override bool Kinematic {
get { return _kinematic; }
set { _kinematic = value; }
}
public override float Buoyancy {
get { return _buoyancy; }
set { _buoyancy = value; }
}
// Used for MoveTo
public override Vector3 PIDTarget {
set { _PIDTarget = value; }
}
public override bool PIDActive {
set { _usePID = value; }
}
public override float PIDTau {
set { _PIDTau = value; }
}
// Used for llSetHoverHeight and maybe vehicle height
// Hover Height will override MoveTo target's Z
public override bool PIDHoverActive {
set { _useHoverPID = value; }
}
public override float PIDHoverHeight {
set { _PIDHoverHeight = value; }
}
public override PIDHoverType PIDHoverType {
set { _PIDHoverType = value; }
}
public override float PIDHoverTau {
set { _PIDHoverTao = value; }
}
// For RotLookAt
public override Quaternion APIDTarget { set { return; } }
public override bool APIDActive { set { return; } }
public override float APIDStrength { set { return; } }
public override float APIDDamping { set { return; } }
public override void AddForce(Vector3 force, bool pushforce) {
if (force.IsFinite())
{
_force.X += force.X;
_force.Y += force.Y;
_force.Z += force.Z;
_scene.TaintedObject(delegate()
{
BulletSimAPI.SetObjectForce(_scene.WorldID, _localID, _force);
});
}
else
{
m_log.WarnFormat("{0}: Got a NaN force applied to a Character", LogHeader);
}
//m_lastUpdateSent = false;
}
public override void AddAngularForce(Vector3 force, bool pushforce) {
}
public override void SetMomentum(Vector3 momentum) {
}
public override void SubscribeEvents(int ms) {
_subscribedEventsMs = ms;
_lastCollisionTime = Util.EnvironmentTickCount() - _subscribedEventsMs; // make first collision happen
}
public override void UnSubscribeEvents() {
_subscribedEventsMs = 0;
}
public override bool SubscribedEvents() {
return (_subscribedEventsMs > 0);
}
// The physics engine says that properties have updated. Update same and inform
// the world that things have changed.
public void UpdateProperties(EntityProperties entprop)
{
bool changed = false;
// we assign to the local variables so the normal set action does not happen
if (_position != entprop.Position)
{
_position = entprop.Position;
changed = true;
}
if (_orientation != entprop.Rotation)
{
_orientation = entprop.Rotation;
changed = true;
}
if (_velocity != entprop.Velocity)
{
_velocity = entprop.Velocity;
changed = true;
}
if (_acceleration != entprop.Acceleration)
{
_acceleration = entprop.Acceleration;
changed = true;
}
if (_rotationalVelocity != entprop.AngularVelocity)
{
_rotationalVelocity = entprop.AngularVelocity;
changed = true;
}
if (changed)
{
// base.RequestPhysicsterseUpdate();
}
}
public void Collide(uint collidingWith, ActorTypes type, Vector3 contactPoint, Vector3 contactNormal, float pentrationDepth)
{
// m_log.DebugFormat("{0}: Collide: ms={1}, id={2}, with={3}", LogHeader, _subscribedEventsMs, LocalID, collidingWith);
// The following makes IsColliding() and IsCollidingGround() work
_collidingStep = _scene.SimulationStep;
if (collidingWith == BSScene.TERRAIN_ID || collidingWith == BSScene.GROUNDPLANE_ID)
{
_collidingGroundStep = _scene.SimulationStep;
}
if (_subscribedEventsMs == 0) return; // don't want collisions
int nowTime = Util.EnvironmentTickCount();
if (nowTime < (_lastCollisionTime + _subscribedEventsMs)) return;
_lastCollisionTime = nowTime;
Dictionary<uint, ContactPoint> contactPoints = new Dictionary<uint, ContactPoint>();
contactPoints.Add(collidingWith, new ContactPoint(contactPoint, contactNormal, pentrationDepth));
CollisionEventUpdate args = new CollisionEventUpdate(LocalID, (int)type, 1, contactPoints);
base.SendCollisionUpdate(args);
}
}
}

View File

@ -0,0 +1,951 @@
/*
* Copyright (c) Contributors, http://opensimulator.org/
* See CONTRIBUTORS.TXT for a full list of copyright holders.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* * Neither the name of the OpenSimulator Project nor the
* names of its contributors may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
/* RA: June 14, 2011. Copied from ODEDynamics.cs and converted to
* call the BulletSim system.
*/
/* Revised Aug, Sept 2009 by Kitto Flora. ODEDynamics.cs replaces
* ODEVehicleSettings.cs. It and ODEPrim.cs are re-organised:
* ODEPrim.cs contains methods dealing with Prim editing, Prim
* characteristics and Kinetic motion.
* ODEDynamics.cs contains methods dealing with Prim Physical motion
* (dynamics) and the associated settings. Old Linear and angular
* motors for dynamic motion have been replace with MoveLinear()
* and MoveAngular(); 'Physical' is used only to switch ODE dynamic
* simualtion on/off; VEHICAL_TYPE_NONE/VEHICAL_TYPE_<other> is to
* switch between 'VEHICLE' parameter use and general dynamics
* settings use.
*/
using System;
using System.Collections.Generic;
using System.Reflection;
using System.Runtime.InteropServices;
using log4net;
using OpenMetaverse;
using OpenSim.Framework;
using OpenSim.Region.Physics.Manager;
namespace OpenSim.Region.Physics.BulletSPlugin
{
public class BSDynamics
{
private int frcount = 0; // Used to limit dynamics debug output to
// every 100th frame
// private BSScene m_parentScene = null;
private BSPrim m_prim; // the prim this dynamic controller belongs to
// Vehicle properties
private Vehicle m_type = Vehicle.TYPE_NONE; // If a 'VEHICLE', and what kind
public Vehicle Type
{
get { return m_type; }
}
// private Quaternion m_referenceFrame = Quaternion.Identity; // Axis modifier
private VehicleFlag m_flags = (VehicleFlag) 0; // Boolean settings:
// HOVER_TERRAIN_ONLY
// HOVER_GLOBAL_HEIGHT
// NO_DEFLECTION_UP
// HOVER_WATER_ONLY
// HOVER_UP_ONLY
// LIMIT_MOTOR_UP
// LIMIT_ROLL_ONLY
private VehicleFlag m_Hoverflags = (VehicleFlag)0;
private Vector3 m_BlockingEndPoint = Vector3.Zero;
private Quaternion m_RollreferenceFrame = Quaternion.Identity;
// Linear properties
private Vector3 m_linearMotorDirection = Vector3.Zero; // velocity requested by LSL, decayed by time
private Vector3 m_linearMotorDirectionLASTSET = Vector3.Zero; // velocity requested by LSL
private Vector3 m_dir = Vector3.Zero; // velocity applied to body
private Vector3 m_linearFrictionTimescale = Vector3.Zero;
private float m_linearMotorDecayTimescale = 0;
private float m_linearMotorTimescale = 0;
private Vector3 m_lastLinearVelocityVector = Vector3.Zero;
private Vector3 m_lastPositionVector = Vector3.Zero;
// private bool m_LinearMotorSetLastFrame = false;
// private Vector3 m_linearMotorOffset = Vector3.Zero;
//Angular properties
private Vector3 m_angularMotorDirection = Vector3.Zero; // angular velocity requested by LSL motor
private int m_angularMotorApply = 0; // application frame counter
private Vector3 m_angularMotorVelocity = Vector3.Zero; // current angular motor velocity
private float m_angularMotorTimescale = 0; // motor angular velocity ramp up rate
private float m_angularMotorDecayTimescale = 0; // motor angular velocity decay rate
private Vector3 m_angularFrictionTimescale = Vector3.Zero; // body angular velocity decay rate
private Vector3 m_lastAngularVelocity = Vector3.Zero; // what was last applied to body
// private Vector3 m_lastVertAttractor = Vector3.Zero; // what VA was last applied to body
//Deflection properties
// private float m_angularDeflectionEfficiency = 0;
// private float m_angularDeflectionTimescale = 0;
// private float m_linearDeflectionEfficiency = 0;
// private float m_linearDeflectionTimescale = 0;
//Banking properties
// private float m_bankingEfficiency = 0;
// private float m_bankingMix = 0;
// private float m_bankingTimescale = 0;
//Hover and Buoyancy properties
private float m_VhoverHeight = 0f;
// private float m_VhoverEfficiency = 0f;
private float m_VhoverTimescale = 0f;
private float m_VhoverTargetHeight = -1.0f; // if <0 then no hover, else its the current target height
private float m_VehicleBuoyancy = 0f; //KF: m_VehicleBuoyancy is set by VEHICLE_BUOYANCY for a vehicle.
// Modifies gravity. Slider between -1 (double-gravity) and 1 (full anti-gravity)
// KF: So far I have found no good method to combine a script-requested .Z velocity and gravity.
// Therefore only m_VehicleBuoyancy=1 (0g) will use the script-requested .Z velocity.
//Attractor properties
private float m_verticalAttractionEfficiency = 1.0f; // damped
private float m_verticalAttractionTimescale = 500f; // Timescale > 300 means no vert attractor.
public BSDynamics(BSPrim myPrim)
{
m_prim = myPrim;
m_type = Vehicle.TYPE_NONE;
}
internal void ProcessFloatVehicleParam(Vehicle pParam, float pValue)
{
switch (pParam)
{
case Vehicle.ANGULAR_DEFLECTION_EFFICIENCY:
if (pValue < 0.01f) pValue = 0.01f;
// m_angularDeflectionEfficiency = pValue;
break;
case Vehicle.ANGULAR_DEFLECTION_TIMESCALE:
if (pValue < 0.01f) pValue = 0.01f;
// m_angularDeflectionTimescale = pValue;
break;
case Vehicle.ANGULAR_MOTOR_DECAY_TIMESCALE:
if (pValue < 0.01f) pValue = 0.01f;
m_angularMotorDecayTimescale = pValue;
break;
case Vehicle.ANGULAR_MOTOR_TIMESCALE:
if (pValue < 0.01f) pValue = 0.01f;
m_angularMotorTimescale = pValue;
break;
case Vehicle.BANKING_EFFICIENCY:
if (pValue < 0.01f) pValue = 0.01f;
// m_bankingEfficiency = pValue;
break;
case Vehicle.BANKING_MIX:
if (pValue < 0.01f) pValue = 0.01f;
// m_bankingMix = pValue;
break;
case Vehicle.BANKING_TIMESCALE:
if (pValue < 0.01f) pValue = 0.01f;
// m_bankingTimescale = pValue;
break;
case Vehicle.BUOYANCY:
if (pValue < -1f) pValue = -1f;
if (pValue > 1f) pValue = 1f;
m_VehicleBuoyancy = pValue;
break;
// case Vehicle.HOVER_EFFICIENCY:
// if (pValue < 0f) pValue = 0f;
// if (pValue > 1f) pValue = 1f;
// m_VhoverEfficiency = pValue;
// break;
case Vehicle.HOVER_HEIGHT:
m_VhoverHeight = pValue;
break;
case Vehicle.HOVER_TIMESCALE:
if (pValue < 0.01f) pValue = 0.01f;
m_VhoverTimescale = pValue;
break;
case Vehicle.LINEAR_DEFLECTION_EFFICIENCY:
if (pValue < 0.01f) pValue = 0.01f;
// m_linearDeflectionEfficiency = pValue;
break;
case Vehicle.LINEAR_DEFLECTION_TIMESCALE:
if (pValue < 0.01f) pValue = 0.01f;
// m_linearDeflectionTimescale = pValue;
break;
case Vehicle.LINEAR_MOTOR_DECAY_TIMESCALE:
if (pValue < 0.01f) pValue = 0.01f;
m_linearMotorDecayTimescale = pValue;
break;
case Vehicle.LINEAR_MOTOR_TIMESCALE:
if (pValue < 0.01f) pValue = 0.01f;
m_linearMotorTimescale = pValue;
break;
case Vehicle.VERTICAL_ATTRACTION_EFFICIENCY:
if (pValue < 0.1f) pValue = 0.1f; // Less goes unstable
if (pValue > 1.0f) pValue = 1.0f;
m_verticalAttractionEfficiency = pValue;
break;
case Vehicle.VERTICAL_ATTRACTION_TIMESCALE:
if (pValue < 0.01f) pValue = 0.01f;
m_verticalAttractionTimescale = pValue;
break;
// These are vector properties but the engine lets you use a single float value to
// set all of the components to the same value
case Vehicle.ANGULAR_FRICTION_TIMESCALE:
m_angularFrictionTimescale = new Vector3(pValue, pValue, pValue);
break;
case Vehicle.ANGULAR_MOTOR_DIRECTION:
m_angularMotorDirection = new Vector3(pValue, pValue, pValue);
m_angularMotorApply = 10;
break;
case Vehicle.LINEAR_FRICTION_TIMESCALE:
m_linearFrictionTimescale = new Vector3(pValue, pValue, pValue);
break;
case Vehicle.LINEAR_MOTOR_DIRECTION:
m_linearMotorDirection = new Vector3(pValue, pValue, pValue);
m_linearMotorDirectionLASTSET = new Vector3(pValue, pValue, pValue);
break;
case Vehicle.LINEAR_MOTOR_OFFSET:
// m_linearMotorOffset = new Vector3(pValue, pValue, pValue);
break;
}
}//end ProcessFloatVehicleParam
internal void ProcessVectorVehicleParam(Vehicle pParam, Vector3 pValue)
{
switch (pParam)
{
case Vehicle.ANGULAR_FRICTION_TIMESCALE:
m_angularFrictionTimescale = new Vector3(pValue.X, pValue.Y, pValue.Z);
break;
case Vehicle.ANGULAR_MOTOR_DIRECTION:
m_angularMotorDirection = new Vector3(pValue.X, pValue.Y, pValue.Z);
// Limit requested angular speed to 2 rps= 4 pi rads/sec
if (m_angularMotorDirection.X > 12.56f) m_angularMotorDirection.X = 12.56f;
if (m_angularMotorDirection.X < - 12.56f) m_angularMotorDirection.X = - 12.56f;
if (m_angularMotorDirection.Y > 12.56f) m_angularMotorDirection.Y = 12.56f;
if (m_angularMotorDirection.Y < - 12.56f) m_angularMotorDirection.Y = - 12.56f;
if (m_angularMotorDirection.Z > 12.56f) m_angularMotorDirection.Z = 12.56f;
if (m_angularMotorDirection.Z < - 12.56f) m_angularMotorDirection.Z = - 12.56f;
m_angularMotorApply = 10;
break;
case Vehicle.LINEAR_FRICTION_TIMESCALE:
m_linearFrictionTimescale = new Vector3(pValue.X, pValue.Y, pValue.Z);
break;
case Vehicle.LINEAR_MOTOR_DIRECTION:
m_linearMotorDirection = new Vector3(pValue.X, pValue.Y, pValue.Z);
m_linearMotorDirectionLASTSET = new Vector3(pValue.X, pValue.Y, pValue.Z);
break;
case Vehicle.LINEAR_MOTOR_OFFSET:
// m_linearMotorOffset = new Vector3(pValue.X, pValue.Y, pValue.Z);
break;
case Vehicle.BLOCK_EXIT:
m_BlockingEndPoint = new Vector3(pValue.X, pValue.Y, pValue.Z);
break;
}
}//end ProcessVectorVehicleParam
internal void ProcessRotationVehicleParam(Vehicle pParam, Quaternion pValue)
{
switch (pParam)
{
case Vehicle.REFERENCE_FRAME:
// m_referenceFrame = pValue;
break;
case Vehicle.ROLL_FRAME:
m_RollreferenceFrame = pValue;
break;
}
}//end ProcessRotationVehicleParam
internal void ProcessVehicleFlags(int pParam, bool remove)
{
if (remove)
{
if (pParam == -1)
{
m_flags = (VehicleFlag)0;
m_Hoverflags = (VehicleFlag)0;
return;
}
if ((pParam & (int)VehicleFlag.HOVER_GLOBAL_HEIGHT) == (int)VehicleFlag.HOVER_GLOBAL_HEIGHT)
{
if ((m_Hoverflags & VehicleFlag.HOVER_GLOBAL_HEIGHT) != (VehicleFlag)0)
m_Hoverflags &= ~(VehicleFlag.HOVER_GLOBAL_HEIGHT);
}
if ((pParam & (int)VehicleFlag.HOVER_TERRAIN_ONLY) == (int)VehicleFlag.HOVER_TERRAIN_ONLY)
{
if ((m_Hoverflags & VehicleFlag.HOVER_TERRAIN_ONLY) != (VehicleFlag)0)
m_Hoverflags &= ~(VehicleFlag.HOVER_TERRAIN_ONLY);
}
if ((pParam & (int)VehicleFlag.HOVER_UP_ONLY) == (int)VehicleFlag.HOVER_UP_ONLY)
{
if ((m_Hoverflags & VehicleFlag.HOVER_UP_ONLY) != (VehicleFlag)0)
m_Hoverflags &= ~(VehicleFlag.HOVER_UP_ONLY);
}
if ((pParam & (int)VehicleFlag.HOVER_WATER_ONLY) == (int)VehicleFlag.HOVER_WATER_ONLY)
{
if ((m_Hoverflags & VehicleFlag.HOVER_WATER_ONLY) != (VehicleFlag)0)
m_Hoverflags &= ~(VehicleFlag.HOVER_WATER_ONLY);
}
if ((pParam & (int)VehicleFlag.LIMIT_MOTOR_UP) == (int)VehicleFlag.LIMIT_MOTOR_UP)
{
if ((m_flags & VehicleFlag.LIMIT_MOTOR_UP) != (VehicleFlag)0)
m_flags &= ~(VehicleFlag.LIMIT_MOTOR_UP);
}
if ((pParam & (int)VehicleFlag.LIMIT_ROLL_ONLY) == (int)VehicleFlag.LIMIT_ROLL_ONLY)
{
if ((m_flags & VehicleFlag.LIMIT_ROLL_ONLY) != (VehicleFlag)0)
m_flags &= ~(VehicleFlag.LIMIT_ROLL_ONLY);
}
if ((pParam & (int)VehicleFlag.MOUSELOOK_BANK) == (int)VehicleFlag.MOUSELOOK_BANK)
{
if ((m_flags & VehicleFlag.MOUSELOOK_BANK) != (VehicleFlag)0)
m_flags &= ~(VehicleFlag.MOUSELOOK_BANK);
}
if ((pParam & (int)VehicleFlag.MOUSELOOK_STEER) == (int)VehicleFlag.MOUSELOOK_STEER)
{
if ((m_flags & VehicleFlag.MOUSELOOK_STEER) != (VehicleFlag)0)
m_flags &= ~(VehicleFlag.MOUSELOOK_STEER);
}
if ((pParam & (int)VehicleFlag.NO_DEFLECTION_UP) == (int)VehicleFlag.NO_DEFLECTION_UP)
{
if ((m_flags & VehicleFlag.NO_DEFLECTION_UP) != (VehicleFlag)0)
m_flags &= ~(VehicleFlag.NO_DEFLECTION_UP);
}
if ((pParam & (int)VehicleFlag.CAMERA_DECOUPLED) == (int)VehicleFlag.CAMERA_DECOUPLED)
{
if ((m_flags & VehicleFlag.CAMERA_DECOUPLED) != (VehicleFlag)0)
m_flags &= ~(VehicleFlag.CAMERA_DECOUPLED);
}
if ((pParam & (int)VehicleFlag.NO_X) == (int)VehicleFlag.NO_X)
{
if ((m_flags & VehicleFlag.NO_X) != (VehicleFlag)0)
m_flags &= ~(VehicleFlag.NO_X);
}
if ((pParam & (int)VehicleFlag.NO_Y) == (int)VehicleFlag.NO_Y)
{
if ((m_flags & VehicleFlag.NO_Y) != (VehicleFlag)0)
m_flags &= ~(VehicleFlag.NO_Y);
}
if ((pParam & (int)VehicleFlag.NO_Z) == (int)VehicleFlag.NO_Z)
{
if ((m_flags & VehicleFlag.NO_Z) != (VehicleFlag)0)
m_flags &= ~(VehicleFlag.NO_Z);
}
if ((pParam & (int)VehicleFlag.LOCK_HOVER_HEIGHT) == (int)VehicleFlag.LOCK_HOVER_HEIGHT)
{
if ((m_Hoverflags & VehicleFlag.LOCK_HOVER_HEIGHT) != (VehicleFlag)0)
m_Hoverflags &= ~(VehicleFlag.LOCK_HOVER_HEIGHT);
}
if ((pParam & (int)VehicleFlag.NO_DEFLECTION) == (int)VehicleFlag.NO_DEFLECTION)
{
if ((m_flags & VehicleFlag.NO_DEFLECTION) != (VehicleFlag)0)
m_flags &= ~(VehicleFlag.NO_DEFLECTION);
}
if ((pParam & (int)VehicleFlag.LOCK_ROTATION) == (int)VehicleFlag.LOCK_ROTATION)
{
if ((m_flags & VehicleFlag.LOCK_ROTATION) != (VehicleFlag)0)
m_flags &= ~(VehicleFlag.LOCK_ROTATION);
}
}
else
{
if ((pParam & (int)VehicleFlag.HOVER_GLOBAL_HEIGHT) == (int)VehicleFlag.HOVER_GLOBAL_HEIGHT)
{
m_Hoverflags |= (VehicleFlag.HOVER_GLOBAL_HEIGHT | m_flags);
}
if ((pParam & (int)VehicleFlag.HOVER_TERRAIN_ONLY) == (int)VehicleFlag.HOVER_TERRAIN_ONLY)
{
m_Hoverflags |= (VehicleFlag.HOVER_TERRAIN_ONLY | m_flags);
}
if ((pParam & (int)VehicleFlag.HOVER_UP_ONLY) == (int)VehicleFlag.HOVER_UP_ONLY)
{
m_Hoverflags |= (VehicleFlag.HOVER_UP_ONLY | m_flags);
}
if ((pParam & (int)VehicleFlag.HOVER_WATER_ONLY) == (int)VehicleFlag.HOVER_WATER_ONLY)
{
m_Hoverflags |= (VehicleFlag.HOVER_WATER_ONLY | m_flags);
}
if ((pParam & (int)VehicleFlag.LIMIT_MOTOR_UP) == (int)VehicleFlag.LIMIT_MOTOR_UP)
{
m_flags |= (VehicleFlag.LIMIT_MOTOR_UP | m_flags);
}
if ((pParam & (int)VehicleFlag.MOUSELOOK_BANK) == (int)VehicleFlag.MOUSELOOK_BANK)
{
m_flags |= (VehicleFlag.MOUSELOOK_BANK | m_flags);
}
if ((pParam & (int)VehicleFlag.MOUSELOOK_STEER) == (int)VehicleFlag.MOUSELOOK_STEER)
{
m_flags |= (VehicleFlag.MOUSELOOK_STEER | m_flags);
}
if ((pParam & (int)VehicleFlag.NO_DEFLECTION_UP) == (int)VehicleFlag.NO_DEFLECTION_UP)
{
m_flags |= (VehicleFlag.NO_DEFLECTION_UP | m_flags);
}
if ((pParam & (int)VehicleFlag.CAMERA_DECOUPLED) == (int)VehicleFlag.CAMERA_DECOUPLED)
{
m_flags |= (VehicleFlag.CAMERA_DECOUPLED | m_flags);
}
if ((pParam & (int)VehicleFlag.NO_X) == (int)VehicleFlag.NO_X)
{
m_flags |= (VehicleFlag.NO_X);
}
if ((pParam & (int)VehicleFlag.NO_Y) == (int)VehicleFlag.NO_Y)
{
m_flags |= (VehicleFlag.NO_Y);
}
if ((pParam & (int)VehicleFlag.NO_Z) == (int)VehicleFlag.NO_Z)
{
m_flags |= (VehicleFlag.NO_Z);
}
if ((pParam & (int)VehicleFlag.LOCK_HOVER_HEIGHT) == (int)VehicleFlag.LOCK_HOVER_HEIGHT)
{
m_Hoverflags |= (VehicleFlag.LOCK_HOVER_HEIGHT);
}
if ((pParam & (int)VehicleFlag.NO_DEFLECTION) == (int)VehicleFlag.NO_DEFLECTION)
{
m_flags |= (VehicleFlag.NO_DEFLECTION);
}
if ((pParam & (int)VehicleFlag.LOCK_ROTATION) == (int)VehicleFlag.LOCK_ROTATION)
{
m_flags |= (VehicleFlag.LOCK_ROTATION);
}
}
}//end ProcessVehicleFlags
internal void ProcessTypeChange(Vehicle pType)
{
// Set Defaults For Type
m_type = pType;
switch (pType)
{
case Vehicle.TYPE_NONE:
m_linearFrictionTimescale = new Vector3(0, 0, 0);
m_angularFrictionTimescale = new Vector3(0, 0, 0);
m_linearMotorDirection = Vector3.Zero;
m_linearMotorTimescale = 0;
m_linearMotorDecayTimescale = 0;
m_angularMotorDirection = Vector3.Zero;
m_angularMotorTimescale = 0;
m_angularMotorDecayTimescale = 0;
m_VhoverHeight = 0;
m_VhoverTimescale = 0;
m_VehicleBuoyancy = 0;
m_flags = (VehicleFlag)0;
break;
case Vehicle.TYPE_SLED:
m_linearFrictionTimescale = new Vector3(30, 1, 1000);
m_angularFrictionTimescale = new Vector3(1000, 1000, 1000);
m_linearMotorDirection = Vector3.Zero;
m_linearMotorTimescale = 1000;
m_linearMotorDecayTimescale = 120;
m_angularMotorDirection = Vector3.Zero;
m_angularMotorTimescale = 1000;
m_angularMotorDecayTimescale = 120;
m_VhoverHeight = 0;
// m_VhoverEfficiency = 1;
m_VhoverTimescale = 10;
m_VehicleBuoyancy = 0;
// m_linearDeflectionEfficiency = 1;
// m_linearDeflectionTimescale = 1;
// m_angularDeflectionEfficiency = 1;
// m_angularDeflectionTimescale = 1000;
// m_bankingEfficiency = 0;
// m_bankingMix = 1;
// m_bankingTimescale = 10;
// m_referenceFrame = Quaternion.Identity;
m_Hoverflags &=
~(VehicleFlag.HOVER_WATER_ONLY | VehicleFlag.HOVER_TERRAIN_ONLY |
VehicleFlag.HOVER_GLOBAL_HEIGHT | VehicleFlag.HOVER_UP_ONLY);
m_flags |= (VehicleFlag.NO_DEFLECTION_UP | VehicleFlag.LIMIT_ROLL_ONLY | VehicleFlag.LIMIT_MOTOR_UP);
break;
case Vehicle.TYPE_CAR:
m_linearFrictionTimescale = new Vector3(100, 2, 1000);
m_angularFrictionTimescale = new Vector3(1000, 1000, 1000);
m_linearMotorDirection = Vector3.Zero;
m_linearMotorTimescale = 1;
m_linearMotorDecayTimescale = 60;
m_angularMotorDirection = Vector3.Zero;
m_angularMotorTimescale = 1;
m_angularMotorDecayTimescale = 0.8f;
m_VhoverHeight = 0;
// m_VhoverEfficiency = 0;
m_VhoverTimescale = 1000;
m_VehicleBuoyancy = 0;
// // m_linearDeflectionEfficiency = 1;
// // m_linearDeflectionTimescale = 2;
// // m_angularDeflectionEfficiency = 0;
// m_angularDeflectionTimescale = 10;
m_verticalAttractionEfficiency = 1f;
m_verticalAttractionTimescale = 10f;
// m_bankingEfficiency = -0.2f;
// m_bankingMix = 1;
// m_bankingTimescale = 1;
// m_referenceFrame = Quaternion.Identity;
m_Hoverflags &= ~(VehicleFlag.HOVER_WATER_ONLY | VehicleFlag.HOVER_TERRAIN_ONLY | VehicleFlag.HOVER_GLOBAL_HEIGHT);
m_flags |= (VehicleFlag.NO_DEFLECTION_UP | VehicleFlag.LIMIT_ROLL_ONLY |
VehicleFlag.LIMIT_MOTOR_UP);
m_Hoverflags |= (VehicleFlag.HOVER_UP_ONLY);
break;
case Vehicle.TYPE_BOAT:
m_linearFrictionTimescale = new Vector3(10, 3, 2);
m_angularFrictionTimescale = new Vector3(10,10,10);
m_linearMotorDirection = Vector3.Zero;
m_linearMotorTimescale = 5;
m_linearMotorDecayTimescale = 60;
m_angularMotorDirection = Vector3.Zero;
m_angularMotorTimescale = 4;
m_angularMotorDecayTimescale = 4;
m_VhoverHeight = 0;
// m_VhoverEfficiency = 0.5f;
m_VhoverTimescale = 2;
m_VehicleBuoyancy = 1;
// m_linearDeflectionEfficiency = 0.5f;
// m_linearDeflectionTimescale = 3;
// m_angularDeflectionEfficiency = 0.5f;
// m_angularDeflectionTimescale = 5;
m_verticalAttractionEfficiency = 0.5f;
m_verticalAttractionTimescale = 5f;
// m_bankingEfficiency = -0.3f;
// m_bankingMix = 0.8f;
// m_bankingTimescale = 1;
// m_referenceFrame = Quaternion.Identity;
m_Hoverflags &= ~(VehicleFlag.HOVER_TERRAIN_ONLY |
VehicleFlag.HOVER_GLOBAL_HEIGHT | VehicleFlag.HOVER_UP_ONLY);
m_flags &= ~(VehicleFlag.LIMIT_ROLL_ONLY);
m_flags |= (VehicleFlag.NO_DEFLECTION_UP |
VehicleFlag.LIMIT_MOTOR_UP);
m_Hoverflags |= (VehicleFlag.HOVER_WATER_ONLY);
break;
case Vehicle.TYPE_AIRPLANE:
m_linearFrictionTimescale = new Vector3(200, 10, 5);
m_angularFrictionTimescale = new Vector3(20, 20, 20);
m_linearMotorDirection = Vector3.Zero;
m_linearMotorTimescale = 2;
m_linearMotorDecayTimescale = 60;
m_angularMotorDirection = Vector3.Zero;
m_angularMotorTimescale = 4;
m_angularMotorDecayTimescale = 4;
m_VhoverHeight = 0;
// m_VhoverEfficiency = 0.5f;
m_VhoverTimescale = 1000;
m_VehicleBuoyancy = 0;
// m_linearDeflectionEfficiency = 0.5f;
// m_linearDeflectionTimescale = 3;
// m_angularDeflectionEfficiency = 1;
// m_angularDeflectionTimescale = 2;
m_verticalAttractionEfficiency = 0.9f;
m_verticalAttractionTimescale = 2f;
// m_bankingEfficiency = 1;
// m_bankingMix = 0.7f;
// m_bankingTimescale = 2;
// m_referenceFrame = Quaternion.Identity;
m_Hoverflags &= ~(VehicleFlag.HOVER_WATER_ONLY | VehicleFlag.HOVER_TERRAIN_ONLY |
VehicleFlag.HOVER_GLOBAL_HEIGHT | VehicleFlag.HOVER_UP_ONLY);
m_flags &= ~(VehicleFlag.NO_DEFLECTION_UP | VehicleFlag.LIMIT_MOTOR_UP);
m_flags |= (VehicleFlag.LIMIT_ROLL_ONLY);
break;
case Vehicle.TYPE_BALLOON:
m_linearFrictionTimescale = new Vector3(5, 5, 5);
m_angularFrictionTimescale = new Vector3(10, 10, 10);
m_linearMotorDirection = Vector3.Zero;
m_linearMotorTimescale = 5;
m_linearMotorDecayTimescale = 60;
m_angularMotorDirection = Vector3.Zero;
m_angularMotorTimescale = 6;
m_angularMotorDecayTimescale = 10;
m_VhoverHeight = 5;
// m_VhoverEfficiency = 0.8f;
m_VhoverTimescale = 10;
m_VehicleBuoyancy = 1;
// m_linearDeflectionEfficiency = 0;
// m_linearDeflectionTimescale = 5;
// m_angularDeflectionEfficiency = 0;
// m_angularDeflectionTimescale = 5;
m_verticalAttractionEfficiency = 1f;
m_verticalAttractionTimescale = 100f;
// m_bankingEfficiency = 0;
// m_bankingMix = 0.7f;
// m_bankingTimescale = 5;
// m_referenceFrame = Quaternion.Identity;
m_Hoverflags &= ~(VehicleFlag.HOVER_WATER_ONLY | VehicleFlag.HOVER_TERRAIN_ONLY |
VehicleFlag.HOVER_UP_ONLY);
m_flags &= ~(VehicleFlag.NO_DEFLECTION_UP | VehicleFlag.LIMIT_MOTOR_UP);
m_flags |= (VehicleFlag.LIMIT_ROLL_ONLY);
m_Hoverflags |= (VehicleFlag.HOVER_GLOBAL_HEIGHT);
break;
}
}//end SetDefaultsForType
internal void Step(float pTimestep, BSScene pParentScene)
{
if (m_type == Vehicle.TYPE_NONE) return;
frcount++; // used to limit debug comment output
if (frcount > 100)
frcount = 0;
MoveLinear(pTimestep, pParentScene);
MoveAngular(pTimestep);
LimitRotation(pTimestep);
}// end Step
private void MoveLinear(float pTimestep, BSScene _pParentScene)
{
if (!m_linearMotorDirection.ApproxEquals(Vector3.Zero, 0.01f)) // requested m_linearMotorDirection is significant
{
// add drive to body
Vector3 addAmount = m_linearMotorDirection/(m_linearMotorTimescale/pTimestep);
m_lastLinearVelocityVector += (addAmount*10); // lastLinearVelocityVector is the current body velocity vector?
// This will work temporarily, but we really need to compare speed on an axis
// KF: Limit body velocity to applied velocity?
if (Math.Abs(m_lastLinearVelocityVector.X) > Math.Abs(m_linearMotorDirectionLASTSET.X))
m_lastLinearVelocityVector.X = m_linearMotorDirectionLASTSET.X;
if (Math.Abs(m_lastLinearVelocityVector.Y) > Math.Abs(m_linearMotorDirectionLASTSET.Y))
m_lastLinearVelocityVector.Y = m_linearMotorDirectionLASTSET.Y;
if (Math.Abs(m_lastLinearVelocityVector.Z) > Math.Abs(m_linearMotorDirectionLASTSET.Z))
m_lastLinearVelocityVector.Z = m_linearMotorDirectionLASTSET.Z;
// decay applied velocity
Vector3 decayfraction = ((Vector3.One/(m_linearMotorDecayTimescale/pTimestep)));
//Console.WriteLine("decay: " + decayfraction);
m_linearMotorDirection -= m_linearMotorDirection * decayfraction * 0.5f;
//Console.WriteLine("actual: " + m_linearMotorDirection);
}
else
{ // requested is not significant
// if what remains of applied is small, zero it.
if (m_lastLinearVelocityVector.ApproxEquals(Vector3.Zero, 0.01f))
m_lastLinearVelocityVector = Vector3.Zero;
}
// convert requested object velocity to world-referenced vector
m_dir = m_lastLinearVelocityVector;
Quaternion rot = m_prim.Orientation;
Quaternion rotq = new Quaternion(rot.X, rot.Y, rot.Z, rot.W); // rotq = rotation of object
m_dir *= rotq; // apply obj rotation to velocity vector
// add Gravity andBuoyancy
// KF: So far I have found no good method to combine a script-requested
// .Z velocity and gravity. Therefore only 0g will used script-requested
// .Z velocity. >0g (m_VehicleBuoyancy < 1) will used modified gravity only.
Vector3 grav = Vector3.Zero;
// There is some gravity, make a gravity force vector
// that is applied after object velocity.
float objMass = m_prim.Mass;
// m_VehicleBuoyancy: -1=2g; 0=1g; 1=0g;
grav.Z = _pParentScene.DefaultGravity.Z * objMass * (1f - m_VehicleBuoyancy);
// Preserve the current Z velocity
Vector3 vel_now = m_prim.Velocity;
m_dir.Z = vel_now.Z; // Preserve the accumulated falling velocity
Vector3 pos = m_prim.Position;
// Vector3 accel = new Vector3(-(m_dir.X - m_lastLinearVelocityVector.X / 0.1f), -(m_dir.Y - m_lastLinearVelocityVector.Y / 0.1f), m_dir.Z - m_lastLinearVelocityVector.Z / 0.1f);
Vector3 posChange = new Vector3();
posChange.X = pos.X - m_lastPositionVector.X;
posChange.Y = pos.Y - m_lastPositionVector.Y;
posChange.Z = pos.Z - m_lastPositionVector.Z;
double Zchange = Math.Abs(posChange.Z);
if (m_BlockingEndPoint != Vector3.Zero)
{
if (pos.X >= (m_BlockingEndPoint.X - (float)1))
{
pos.X -= posChange.X + 1;
m_prim.Position = pos;
}
if (pos.Y >= (m_BlockingEndPoint.Y - (float)1))
{
pos.Y -= posChange.Y + 1;
m_prim.Position = pos;
}
if (pos.Z >= (m_BlockingEndPoint.Z - (float)1))
{
pos.Z -= posChange.Z + 1;
m_prim.Position = pos;
}
if (pos.X <= 0)
{
pos.X += posChange.X + 1;
m_prim.Position = pos;
}
if (pos.Y <= 0)
{
pos.Y += posChange.Y + 1;
m_prim.Position = pos;
}
}
if (pos.Z < _pParentScene.GetTerrainHeightAtXY(pos.X, pos.Y))
{
pos.Z = _pParentScene.GetTerrainHeightAtXY(pos.X, pos.Y) + 2;
m_prim.Position = pos;
}
// Check if hovering
if ((m_Hoverflags & (VehicleFlag.HOVER_WATER_ONLY | VehicleFlag.HOVER_TERRAIN_ONLY | VehicleFlag.HOVER_GLOBAL_HEIGHT)) != 0)
{
// We should hover, get the target height
if ((m_Hoverflags & VehicleFlag.HOVER_WATER_ONLY) != 0)
{
m_VhoverTargetHeight = _pParentScene.GetWaterLevel() + m_VhoverHeight;
}
if ((m_Hoverflags & VehicleFlag.HOVER_TERRAIN_ONLY) != 0)
{
m_VhoverTargetHeight = _pParentScene.GetTerrainHeightAtXY(pos.X, pos.Y) + m_VhoverHeight;
}
if ((m_Hoverflags & VehicleFlag.HOVER_GLOBAL_HEIGHT) != 0)
{
m_VhoverTargetHeight = m_VhoverHeight;
}
if ((m_Hoverflags & VehicleFlag.HOVER_UP_ONLY) != 0)
{
// If body is aready heigher, use its height as target height
if (pos.Z > m_VhoverTargetHeight) m_VhoverTargetHeight = pos.Z;
}
if ((m_Hoverflags & VehicleFlag.LOCK_HOVER_HEIGHT) != 0)
{
if ((pos.Z - m_VhoverTargetHeight) > .2 || (pos.Z - m_VhoverTargetHeight) < -.2)
{
m_prim.Position = pos;
}
}
else
{
float herr0 = pos.Z - m_VhoverTargetHeight;
// Replace Vertical speed with correction figure if significant
if (Math.Abs(herr0) > 0.01f)
{
m_dir.Z = -((herr0 * pTimestep * 50.0f) / m_VhoverTimescale);
//KF: m_VhoverEfficiency is not yet implemented
}
else
{
m_dir.Z = 0f;
}
}
// m_VhoverEfficiency = 0f; // 0=boucy, 1=Crit.damped
// m_VhoverTimescale = 0f; // time to acheive height
// pTimestep is time since last frame,in secs
}
if ((m_flags & (VehicleFlag.LIMIT_MOTOR_UP)) != 0)
{
//Start Experimental Values
if (Zchange > .3)
{
grav.Z = (float)(grav.Z * 3);
}
if (Zchange > .15)
{
grav.Z = (float)(grav.Z * 2);
}
if (Zchange > .75)
{
grav.Z = (float)(grav.Z * 1.5);
}
if (Zchange > .05)
{
grav.Z = (float)(grav.Z * 1.25);
}
if (Zchange > .025)
{
grav.Z = (float)(grav.Z * 1.125);
}
float terraintemp = _pParentScene.GetTerrainHeightAtXY(pos.X, pos.Y);
float postemp = (pos.Z - terraintemp);
if (postemp > 2.5f)
{
grav.Z = (float)(grav.Z * 1.037125);
}
//End Experimental Values
}
if ((m_flags & (VehicleFlag.NO_X)) != 0)
{
m_dir.X = 0;
}
if ((m_flags & (VehicleFlag.NO_Y)) != 0)
{
m_dir.Y = 0;
}
if ((m_flags & (VehicleFlag.NO_Z)) != 0)
{
m_dir.Z = 0;
}
m_lastPositionVector = m_prim.Position;
// Apply velocity
m_prim.Velocity = m_dir;
// apply gravity force
m_prim.Force = grav;
// apply friction
Vector3 decayamount = Vector3.One / (m_linearFrictionTimescale / pTimestep);
m_lastLinearVelocityVector -= m_lastLinearVelocityVector * decayamount;
} // end MoveLinear()
private void MoveAngular(float pTimestep)
{
/*
private Vector3 m_angularMotorDirection = Vector3.Zero; // angular velocity requested by LSL motor
private int m_angularMotorApply = 0; // application frame counter
private float m_angularMotorVelocity = 0; // current angular motor velocity (ramps up and down)
private float m_angularMotorTimescale = 0; // motor angular velocity ramp up rate
private float m_angularMotorDecayTimescale = 0; // motor angular velocity decay rate
private Vector3 m_angularFrictionTimescale = Vector3.Zero; // body angular velocity decay rate
private Vector3 m_lastAngularVelocity = Vector3.Zero; // what was last applied to body
*/
// Get what the body is doing, this includes 'external' influences
Vector3 angularVelocity = m_prim.AngularVelocity;
// Vector3 angularVelocity = Vector3.Zero;
if (m_angularMotorApply > 0)
{
// ramp up to new value
// current velocity += error / (time to get there / step interval)
// requested speed - last motor speed
m_angularMotorVelocity.X += (m_angularMotorDirection.X - m_angularMotorVelocity.X) / (m_angularMotorTimescale / pTimestep);
m_angularMotorVelocity.Y += (m_angularMotorDirection.Y - m_angularMotorVelocity.Y) / (m_angularMotorTimescale / pTimestep);
m_angularMotorVelocity.Z += (m_angularMotorDirection.Z - m_angularMotorVelocity.Z) / (m_angularMotorTimescale / pTimestep);
m_angularMotorApply--; // This is done so that if script request rate is less than phys frame rate the expected
// velocity may still be acheived.
}
else
{
// no motor recently applied, keep the body velocity
/* m_angularMotorVelocity.X = angularVelocity.X;
m_angularMotorVelocity.Y = angularVelocity.Y;
m_angularMotorVelocity.Z = angularVelocity.Z; */
// and decay the velocity
m_angularMotorVelocity -= m_angularMotorVelocity / (m_angularMotorDecayTimescale / pTimestep);
} // end motor section
// Vertical attractor section
Vector3 vertattr = Vector3.Zero;
if (m_verticalAttractionTimescale < 300)
{
float VAservo = 0.2f / (m_verticalAttractionTimescale * pTimestep);
// get present body rotation
Quaternion rotq = m_prim.Orientation;
// make a vector pointing up
Vector3 verterr = Vector3.Zero;
verterr.Z = 1.0f;
// rotate it to Body Angle
verterr = verterr * rotq;
// verterr.X and .Y are the World error ammounts. They are 0 when there is no error (Vehicle Body is 'vertical'), and .Z will be 1.
// As the body leans to its side |.X| will increase to 1 and .Z fall to 0. As body inverts |.X| will fall and .Z will go
// negative. Similar for tilt and |.Y|. .X and .Y must be modulated to prevent a stable inverted body.
if (verterr.Z < 0.0f)
{
verterr.X = 2.0f - verterr.X;
verterr.Y = 2.0f - verterr.Y;
}
// Error is 0 (no error) to +/- 2 (max error)
// scale it by VAservo
verterr = verterr * VAservo;
//if (frcount == 0) Console.WriteLine("VAerr=" + verterr);
// As the body rotates around the X axis, then verterr.Y increases; Rotated around Y then .X increases, so
// Change Body angular velocity X based on Y, and Y based on X. Z is not changed.
vertattr.X = verterr.Y;
vertattr.Y = - verterr.X;
vertattr.Z = 0f;
// scaling appears better usingsquare-law
float bounce = 1.0f - (m_verticalAttractionEfficiency * m_verticalAttractionEfficiency);
vertattr.X += bounce * angularVelocity.X;
vertattr.Y += bounce * angularVelocity.Y;
} // else vertical attractor is off
// m_lastVertAttractor = vertattr;
// Bank section tba
// Deflection section tba
// Sum velocities
m_lastAngularVelocity = m_angularMotorVelocity + vertattr; // + bank + deflection
if ((m_flags & (VehicleFlag.NO_DEFLECTION_UP)) != 0)
{
m_lastAngularVelocity.X = 0;
m_lastAngularVelocity.Y = 0;
}
if (m_lastAngularVelocity.ApproxEquals(Vector3.Zero, 0.01f))
{
m_lastAngularVelocity = Vector3.Zero; // Reduce small value to zero.
}
// apply friction
Vector3 decayamount = Vector3.One / (m_angularFrictionTimescale / pTimestep);
m_lastAngularVelocity -= m_lastAngularVelocity * decayamount;
// Apply to the body
m_prim.AngularVelocity = m_lastAngularVelocity;
} //end MoveAngular
internal void LimitRotation(float timestep)
{
Quaternion rotq = m_prim.Orientation; // rotq = rotation of object
Quaternion m_rot = rotq;
bool changed = false;
if (m_RollreferenceFrame != Quaternion.Identity)
{
if (rotq.X >= m_RollreferenceFrame.X)
{
m_rot.X = rotq.X - (m_RollreferenceFrame.X / 2);
}
if (rotq.Y >= m_RollreferenceFrame.Y)
{
m_rot.Y = rotq.Y - (m_RollreferenceFrame.Y / 2);
}
if (rotq.X <= -m_RollreferenceFrame.X)
{
m_rot.X = rotq.X + (m_RollreferenceFrame.X / 2);
}
if (rotq.Y <= -m_RollreferenceFrame.Y)
{
m_rot.Y = rotq.Y + (m_RollreferenceFrame.Y / 2);
}
changed = true;
}
if ((m_flags & VehicleFlag.LOCK_ROTATION) != 0)
{
m_rot.X = 0;
m_rot.Y = 0;
changed = true;
}
if (changed)
m_prim.Orientation = m_rot;
}
}
}

View File

@ -0,0 +1,68 @@
/*
* Copyright (c) Contributors, http://opensimulator.org/
* See CONTRIBUTORS.TXT for a full list of copyright holders.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyrightD
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* * Neither the name of the OpenSimulator Project nor the
* names of its contributors may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
using System;
using System.Collections.Generic;
using OpenSim.Framework;
using OpenSim.Region.Physics.Manager;
using OpenMetaverse;
namespace OpenSim.Region.Physics.BulletSPlugin
{
public class BSPlugin : IPhysicsPlugin
{
//private static readonly log4net.ILog m_log = log4net.LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType);
private BSScene _mScene;
public BSPlugin()
{
}
public bool Init()
{
return true;
}
public PhysicsScene GetScene(String sceneIdentifier)
{
if (_mScene == null)
{
_mScene = new BSScene(sceneIdentifier);
}
return (_mScene);
}
public string GetName()
{
return ("BulletSim");
}
public void Dispose()
{
}
}
}

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,553 @@
/*
* Copyright (c) Contributors, http://opensimulator.org/
* See CONTRIBUTORS.TXT for a full list of copyright holders.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyrightD
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* * Neither the name of the OpenSimulator Project nor the
* names of its contributors may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
using System;
using System.Collections.Generic;
using System.Runtime.InteropServices;
using System.Text;
using System.Threading;
using Nini.Config;
using log4net;
using OpenSim.Framework;
using OpenSim.Region.Physics.Manager;
using OpenMetaverse;
using OpenSim.Region.Framework;
// TODOs for BulletSim (for BSScene, BSPrim, BSCharacter and BulletSim)
// Fix folding up feet
// Fix terrain. Only flat terrain works. Terrain with shape is oriented wrong? Origined wrong?
// Parameterize BulletSim. Pass a structure of parameters to the C++ code. Capsule size, friction, ...
// Shift drag duplication of objects does not work
// Adjust character capsule size when height is adjusted (ScenePresence.SetHeight)
// Test sculpties
// Compute physics FPS reasonably
// Based on material, set density and friction
// More efficient memory usage in passing hull information from BSPrim to BulletSim
// Four states of prim: Physical, regular, phantom and selected. Are we modeling these correctly?
// In SL one can set both physical and phantom (gravity, does not effect others, makes collisions with ground)
// At the moment, physical and phantom causes object to drop through the terrain
// Should prim.link() and prim.delink() membership checking happen at taint time?
// Mesh sharing. Use meshHash to tell if we already have a hull of that shape and only create once
// Do attachments need to be handled separately? Need collision events. Do not collide with VolumeDetect
// Implement the genCollisions feature in BulletSim::SetObjectProperties (don't pass up unneeded collisions)
// Implement LockAngularMotion
// Decide if clearing forces is the right thing to do when setting position (BulletSim::SetObjectTranslation)
// Built Galton board (lots of MoveTo's) and some slats were not positioned correctly (mistakes scattered)
// No mistakes with ODE. Shape creation race condition?
// Does NeedsMeshing() really need to exclude all the different shapes?
//
namespace OpenSim.Region.Physics.BulletSPlugin
{
public class BSScene : PhysicsScene
{
private static readonly ILog m_log = LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType);
private static readonly string LogHeader = "[BULLETS SCENE]";
private Dictionary<uint, BSCharacter> m_avatars = new Dictionary<uint, BSCharacter>();
private Dictionary<uint, BSPrim> m_prims = new Dictionary<uint, BSPrim>();
private List<BSPrim> m_vehicles = new List<BSPrim>();
private float[] m_heightMap;
private float m_waterLevel;
private uint m_worldID;
public uint WorldID { get { return m_worldID; } }
public IMesher mesher;
public int meshLOD = 32;
private int m_maxSubSteps = 10;
private float m_fixedTimeStep = 1f / 60f;
private long m_simulationStep = 0;
public long SimulationStep { get { return m_simulationStep; } }
private bool _meshSculptedPrim = true; // cause scuplted prims to get meshed
private bool _forceSimplePrimMeshing = false; // if a cube or sphere, let Bullet do internal shapes
public float maximumMassObject = 10000.01f;
public const uint TERRAIN_ID = 0;
public const uint GROUNDPLANE_ID = 1;
public float DefaultFriction = 0.70f;
public float DefaultDensity = 10.000006836f; // Aluminum g/cm3; TODO: compute based on object material
public Vector3 DefaultGravity = new Vector3(0, 0, -9.80665f);
public delegate void TaintCallback();
private List<TaintCallback> _taintedObjects;
private Object _taintLock = new Object();
private BulletSimAPI.DebugLogCallback debugLogCallbackHandle;
public BSScene(string identifier)
{
}
public override void Initialise(IMesher meshmerizer, IConfigSource config)
{
if (config != null)
{
IConfig pConfig = config.Configs["BulletSim"];
if (pConfig != null)
{
DefaultFriction = pConfig.GetFloat("Friction", DefaultFriction);
DefaultDensity = pConfig.GetFloat("Density", DefaultDensity);
// TODO: a lot more parameters that are passed to BulletSim
}
}
// if Debug, enable logging from the unmanaged code
if (m_log.IsDebugEnabled)
{
m_log.DebugFormat("{0}: Initialize: Setting debug callback for unmanaged code", LogHeader);
debugLogCallbackHandle = new BulletSimAPI.DebugLogCallback(BulletLogger);
BulletSimAPI.SetDebugLogCallback(debugLogCallbackHandle);
}
_meshSculptedPrim = true; // mesh sculpted prims
_forceSimplePrimMeshing = false; // use complex meshing if called for
_taintedObjects = new List<TaintCallback>();
mesher = meshmerizer;
// m_log.DebugFormat("{0}: Initialize: Calling BulletSimAPI.Initialize.", LogHeader);
m_worldID = BulletSimAPI.Initialize(new Vector3(Constants.RegionSize, Constants.RegionSize, 4096f));
}
// Called directly from unmanaged code so don't do much
private void BulletLogger(string msg)
{
m_log.Debug("[BULLETS UNMANAGED]:" + msg);
}
public override PhysicsActor AddAvatar(string avName, Vector3 position, Vector3 size, bool isFlying)
{
m_log.ErrorFormat("{0}: CALL TO AddAvatar in BSScene. NOT IMPLEMENTED", LogHeader);
return null;
}
public override PhysicsActor AddAvatar(uint localID, string avName, Vector3 position, Vector3 size, bool isFlying)
{
// m_log.DebugFormat("{0}: AddAvatar: {1}", LogHeader, avName);
BSCharacter actor = new BSCharacter(localID, avName, this, position, size, isFlying);
lock (m_avatars) m_avatars.Add(localID, actor);
return actor;
}
public override void RemoveAvatar(PhysicsActor actor)
{
// m_log.DebugFormat("{0}: RemoveAvatar", LogHeader);
if (actor is BSCharacter)
{
((BSCharacter)actor).Destroy();
}
try
{
lock (m_avatars) m_avatars.Remove(actor.LocalID);
}
catch (Exception e)
{
m_log.WarnFormat("{0}: Attempt to remove avatar that is not in physics scene: {1}", LogHeader, e);
}
}
public override void RemovePrim(PhysicsActor prim)
{
// m_log.DebugFormat("{0}: RemovePrim", LogHeader);
if (prim is BSPrim)
{
((BSPrim)prim).Destroy();
}
try
{
lock (m_prims) m_prims.Remove(prim.LocalID);
}
catch (Exception e)
{
m_log.WarnFormat("{0}: Attempt to remove prim that is not in physics scene: {1}", LogHeader, e);
}
}
public override PhysicsActor AddPrimShape(string primName, PrimitiveBaseShape pbs, Vector3 position,
Vector3 size, Quaternion rotation) // deprecated
{
return null;
}
public override PhysicsActor AddPrimShape(string primName, PrimitiveBaseShape pbs, Vector3 position,
Vector3 size, Quaternion rotation, bool isPhysical)
{
m_log.ErrorFormat("{0}: CALL TO AddPrimShape in BSScene. NOT IMPLEMENTED", LogHeader);
return null;
}
public override PhysicsActor AddPrimShape(uint localID, string primName, PrimitiveBaseShape pbs, Vector3 position,
Vector3 size, Quaternion rotation, bool isPhysical)
{
// m_log.DebugFormat("{0}: AddPrimShape2: {1}", LogHeader, primName);
IMesh mesh = null;
if (NeedsMeshing(pbs))
{
// if the prim is complex, create the mesh for it.
// If simple (box or sphere) leave 'mesh' null and physics will do a native shape.
mesh = mesher.CreateMesh(primName, pbs, size, this.meshLOD, isPhysical);
}
BSPrim prim = new BSPrim(localID, primName, this, position, size, rotation, mesh, pbs, isPhysical);
lock (m_prims) m_prims.Add(localID, prim);
return prim;
}
// This is a call from the simulator saying that some physical property has been updated.
// The BulletS driver senses the changing of relevant properties so this taint
// information call is not needed.
public override void AddPhysicsActorTaint(PhysicsActor prim) { }
// Simulate one timestep
public override float Simulate(float timeStep)
{
int updatedEntityCount;
IntPtr updatedEntitiesPtr;
IntPtr[] updatedEntities;
int collidersCount;
IntPtr collidersPtr;
int[] colliders; // should be uint but Marshal.Copy does not have that overload
// update the prim states while we know the physics engine is not busy
ProcessTaints();
// Some of the prims operate with special vehicle properties
ProcessVehicles(timeStep);
ProcessTaints(); // the vehicles might have added taints
// step the physical world one interval
m_simulationStep++;
int numSubSteps = BulletSimAPI.PhysicsStep(m_worldID, timeStep, m_maxSubSteps, m_fixedTimeStep,
out updatedEntityCount, out updatedEntitiesPtr, out collidersCount, out collidersPtr);
// if there were collisions, they show up here
if (collidersCount > 0)
{
colliders = new int[collidersCount];
Marshal.Copy(collidersPtr, colliders, 0, collidersCount);
for (int ii = 0; ii < collidersCount; ii+=2)
{
uint cA = (uint)colliders[ii];
uint cB = (uint)colliders[ii+1];
SendCollision(cA, cB);
SendCollision(cB, cA);
}
}
// if any of the objects had updated properties, they are returned in the updatedEntity structure
// TODO: figure out how to pass all of the EntityProperties structures in one marshal call.
if (updatedEntityCount > 0)
{
updatedEntities = new IntPtr[updatedEntityCount];
// fetch all the pointers to all the EntityProperties structures for these updates
Marshal.Copy(updatedEntitiesPtr, updatedEntities, 0, updatedEntityCount);
for (int ii = 0; ii < updatedEntityCount; ii++)
{
IntPtr updatePointer = updatedEntities[ii];
EntityProperties entprop = (EntityProperties)Marshal.PtrToStructure(updatePointer, typeof(EntityProperties));
// m_log.DebugFormat("{0}: entprop: id={1}, pos={2}", LogHeader, entprop.ID, entprop.Position);
BSCharacter actor;
if (m_avatars.TryGetValue(entprop.ID, out actor))
{
actor.UpdateProperties(entprop);
continue;
}
BSPrim prim;
if (m_prims.TryGetValue(entprop.ID, out prim))
{
prim.UpdateProperties(entprop);
}
}
}
// fps calculation wrong. This calculation returns about 1 in normal operation.
return timeStep / (numSubSteps * m_fixedTimeStep) * 1000f;
}
// Something has collided
private void SendCollision(uint localID, uint collidingWith)
{
if (localID == TERRAIN_ID || localID == GROUNDPLANE_ID)
{
// we never send collisions to the terrain
return;
}
ActorTypes type = ActorTypes.Prim;
if (collidingWith == TERRAIN_ID || collidingWith == GROUNDPLANE_ID)
type = ActorTypes.Ground;
else if (m_avatars.ContainsKey(collidingWith))
type = ActorTypes.Agent;
BSPrim prim;
if (m_prims.TryGetValue(localID, out prim)) {
prim.Collide(collidingWith, type, Vector3.Zero, Vector3.UnitZ, 0.01f);
return;
}
BSCharacter actor;
if (m_avatars.TryGetValue(localID, out actor)) {
actor.Collide(collidingWith, type, Vector3.Zero, Vector3.UnitZ, 0.01f);
return;
}
return;
}
public override void GetResults() { }
public override void SetTerrain(float[] heightMap) {
m_log.DebugFormat("{0}: SetTerrain", LogHeader);
m_heightMap = heightMap;
this.TaintedObject(delegate()
{
BulletSimAPI.SetHeightmap(m_worldID, m_heightMap);
});
}
public float GetTerrainHeightAtXY(float tX, float tY)
{
return m_heightMap[((int)tX) * Constants.RegionSize + ((int)tY)];
}
public override void SetWaterLevel(float baseheight)
{
m_waterLevel = baseheight;
}
public float GetWaterLevel()
{
return m_waterLevel;
}
public override void DeleteTerrain()
{
m_log.DebugFormat("{0}: DeleteTerrain()", LogHeader);
}
public override void Dispose()
{
m_log.DebugFormat("{0}: Dispose()", LogHeader);
}
public override Dictionary<uint, float> GetTopColliders()
{
return new Dictionary<uint, float>();
}
public override bool IsThreaded { get { return false; } }
/// <summary>
/// Routine to figure out if we need to mesh this prim with our mesher
/// </summary>
/// <param name="pbs"></param>
/// <returns>true if the prim needs meshing</returns>
public bool NeedsMeshing(PrimitiveBaseShape pbs)
{
// most of this is redundant now as the mesher will return null if it cant mesh a prim
// but we still need to check for sculptie meshing being enabled so this is the most
// convenient place to do it for now...
// int iPropertiesNotSupportedDefault = 0;
if (pbs.SculptEntry && !_meshSculptedPrim)
{
// m_log.DebugFormat("{0}: NeedsMeshing: scultpy mesh", LogHeader);
return false;
}
// if it's a standard box or sphere with no cuts, hollows, twist or top shear, return false since Bullet
// can use an internal representation for the prim
if (!_forceSimplePrimMeshing)
{
// m_log.DebugFormat("{0}: NeedsMeshing: simple mesh: profshape={1}, curve={2}", LogHeader, pbs.ProfileShape, pbs.PathCurve);
if ((pbs.ProfileShape == ProfileShape.Square && pbs.PathCurve == (byte)Extrusion.Straight)
|| (pbs.ProfileShape == ProfileShape.HalfCircle && pbs.PathCurve == (byte)Extrusion.Curve1
&& pbs.Scale.X == pbs.Scale.Y && pbs.Scale.Y == pbs.Scale.Z))
{
if (pbs.ProfileBegin == 0 && pbs.ProfileEnd == 0
&& pbs.ProfileHollow == 0
&& pbs.PathTwist == 0 && pbs.PathTwistBegin == 0
&& pbs.PathBegin == 0 && pbs.PathEnd == 0
&& pbs.PathTaperX == 0 && pbs.PathTaperY == 0
&& pbs.PathScaleX == 100 && pbs.PathScaleY == 100
&& pbs.PathShearX == 0 && pbs.PathShearY == 0)
{
return false;
}
}
}
/* TODO: verify that the mesher will now do all these shapes
if (pbs.ProfileHollow != 0)
iPropertiesNotSupportedDefault++;
if ((pbs.PathBegin != 0) || pbs.PathEnd != 0)
iPropertiesNotSupportedDefault++;
if ((pbs.PathTwistBegin != 0) || (pbs.PathTwist != 0))
iPropertiesNotSupportedDefault++;
if ((pbs.ProfileBegin != 0) || pbs.ProfileEnd != 0)
iPropertiesNotSupportedDefault++;
if ((pbs.PathScaleX != 100) || (pbs.PathScaleY != 100))
iPropertiesNotSupportedDefault++;
if ((pbs.PathShearX != 0) || (pbs.PathShearY != 0))
iPropertiesNotSupportedDefault++;
if (pbs.ProfileShape == ProfileShape.Circle && pbs.PathCurve == (byte)Extrusion.Straight)
iPropertiesNotSupportedDefault++;
if (pbs.ProfileShape == ProfileShape.HalfCircle && pbs.PathCurve == (byte)Extrusion.Curve1 && (pbs.Scale.X != pbs.Scale.Y || pbs.Scale.Y != pbs.Scale.Z || pbs.Scale.Z != pbs.Scale.X))
iPropertiesNotSupportedDefault++;
if (pbs.ProfileShape == ProfileShape.HalfCircle && pbs.PathCurve == (byte) Extrusion.Curve1)
iPropertiesNotSupportedDefault++;
// test for torus
if ((pbs.ProfileCurve & 0x07) == (byte)ProfileShape.Square)
{
if (pbs.PathCurve == (byte)Extrusion.Curve1)
{
iPropertiesNotSupportedDefault++;
}
}
else if ((pbs.ProfileCurve & 0x07) == (byte)ProfileShape.Circle)
{
if (pbs.PathCurve == (byte)Extrusion.Straight)
{
iPropertiesNotSupportedDefault++;
}
// ProfileCurve seems to combine hole shape and profile curve so we need to only compare against the lower 3 bits
else if (pbs.PathCurve == (byte)Extrusion.Curve1)
{
iPropertiesNotSupportedDefault++;
}
}
else if ((pbs.ProfileCurve & 0x07) == (byte)ProfileShape.HalfCircle)
{
if (pbs.PathCurve == (byte)Extrusion.Curve1 || pbs.PathCurve == (byte)Extrusion.Curve2)
{
iPropertiesNotSupportedDefault++;
}
}
else if ((pbs.ProfileCurve & 0x07) == (byte)ProfileShape.EquilateralTriangle)
{
if (pbs.PathCurve == (byte)Extrusion.Straight)
{
iPropertiesNotSupportedDefault++;
}
else if (pbs.PathCurve == (byte)Extrusion.Curve1)
{
iPropertiesNotSupportedDefault++;
}
}
if (iPropertiesNotSupportedDefault == 0)
{
return false;
}
*/
return true;
}
// The calls to the PhysicsActors can't directly call into the physics engine
// because it might be busy. We we delay changes to a known time.
// We rely on C#'s closure to save and restore the context for the delegate.
public void TaintedObject(TaintCallback callback)
{
lock (_taintLock)
_taintedObjects.Add(callback);
return;
}
// When someone tries to change a property on a BSPrim or BSCharacter, the object queues
// a callback into itself to do the actual property change. That callback is called
// here just before the physics engine is called to step the simulation.
public void ProcessTaints()
{
if (_taintedObjects.Count > 0) // save allocating new list if there is nothing to process
{
// swizzle a new list into the list location so we can process what's there
List<TaintCallback> oldList;
lock (_taintLock)
{
oldList = _taintedObjects;
_taintedObjects = new List<TaintCallback>();
}
foreach (TaintCallback callback in oldList)
{
try
{
callback();
}
catch (Exception e)
{
m_log.ErrorFormat("{0}: ProcessTaints: Exception: {1}", LogHeader, e);
}
}
oldList.Clear();
}
}
#region Vehicles
// Make so the scene will call this prim for vehicle actions each tick.
// Safe to call if prim is already in the vehicle list.
public void AddVehiclePrim(BSPrim vehicle)
{
lock (m_vehicles)
{
if (!m_vehicles.Contains(vehicle))
{
m_vehicles.Add(vehicle);
}
}
}
// Remove a prim from our list of vehicles.
// Safe to call if the prim is not in the vehicle list.
public void RemoveVehiclePrim(BSPrim vehicle)
{
lock (m_vehicles)
{
if (m_vehicles.Contains(vehicle))
{
m_vehicles.Remove(vehicle);
}
}
}
// Some prims have extra vehicle actions
// no locking because only called when physics engine is not busy
private void ProcessVehicles(float timeStep)
{
foreach (BSPrim prim in m_vehicles)
{
prim.StepVehicle(timeStep);
}
}
#endregion Vehicles
}
}

View File

@ -0,0 +1,186 @@
/*
* Copyright (c) Contributors, http://opensimulator.org/
* See CONTRIBUTORS.TXT for a full list of copyright holders.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyrightD
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* * Neither the name of the OpenSimulator Project nor the
* names of its contributors may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
using System;
using System.Runtime.InteropServices;
using System.Security;
using System.Text;
using OpenMetaverse;
namespace OpenSim.Region.Physics.BulletSPlugin {
public struct ConvexHull
{
Vector3 Offset;
int VertexCount;
Vector3[] Vertices;
}
public struct ShapeData
{
public enum PhysicsShapeType
{
SHAPE_AVATAR = 0,
SHAPE_BOX = 1,
SHAPE_CONE = 2,
SHAPE_CYLINDER = 3,
SHAPE_SPHERE = 4,
SHAPE_HULL = 5
};
public const int numericTrue = 1;
public const int numericFalse = 0;
public uint ID;
public PhysicsShapeType Type;
public Vector3 Position;
public Quaternion Rotation;
public Vector3 Velocity;
public Vector3 Scale;
public float Mass;
public float Buoyancy;
public System.UInt64 MeshKey;
public int Collidable;
public float Friction;
public int Static; // true if a static object. Otherwise gravity, etc.
// note that bools are passed as ints since bool size changes by language
}
public struct SweepHit
{
public uint ID;
public float Fraction;
public Vector3 Normal;
public Vector3 Point;
}
public struct RaycastHit
{
public uint ID;
public float Fraction;
public Vector3 Normal;
}
public struct EntityProperties
{
public uint ID;
public Vector3 Position;
public Quaternion Rotation;
public Vector3 Velocity;
public Vector3 Acceleration;
public Vector3 AngularVelocity;
}
static class BulletSimAPI {
[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
public static extern uint Initialize(Vector3 maxPosition);
[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
public static extern void SetHeightmap(uint worldID, [MarshalAs(UnmanagedType.LPArray)] float[] heightMap);
[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
public static extern void Shutdown(uint worldID);
[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
public static extern int PhysicsStep(uint worldID, float timeStep, int maxSubSteps, float fixedTimeStep,
out int updatedEntityCount,
out IntPtr updatedEntitiesPtr,
out int collidersCount,
out IntPtr collidersPtr);
[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
public static extern bool CreateHull(uint worldID, System.UInt64 meshKey, int hullCount,
[MarshalAs(UnmanagedType.LPArray)] float[] hulls
);
[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
public static extern bool DestroyHull(uint worldID, System.UInt64 meshKey);
[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
public static extern bool CreateObject(uint worldID, ShapeData shapeData);
[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
public static extern void CreateLinkset(uint worldID, int objectCount, ShapeData[] shapeDatas);
[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
public static extern void AddConstraint(uint worldID, uint id1, uint id2,
Vector3 frame1, Vector3 frame2, Vector3 lowLinear, Vector3 hiLinear, Vector3 lowAngular, Vector3 hiAngular);
[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
public static extern bool RemoveConstraint(uint worldID, uint id1, uint id2);
[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
public static extern Vector3 GetObjectPosition(uint WorldID, uint id);
[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
public static extern bool SetObjectTranslation(uint worldID, uint id, Vector3 position, Quaternion rotation);
[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
public static extern bool SetObjectVelocity(uint worldID, uint id, Vector3 velocity);
[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
public static extern bool SetObjectAngularVelocity(uint worldID, uint id, Vector3 angularVelocity);
[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
public static extern bool SetObjectForce(uint worldID, uint id, Vector3 force);
[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
public static extern bool SetObjectScaleMass(uint worldID, uint id, Vector3 scale, float mass, bool isDynamic);
[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
public static extern bool SetObjectCollidable(uint worldID, uint id, bool phantom);
[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
public static extern bool SetObjectDynamic(uint worldID, uint id, bool isDynamic, float mass);
[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
public static extern bool SetObjectGhost(uint worldID, uint id, bool ghostly);
[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
public static extern bool SetObjectProperties(uint worldID, uint id, bool isStatic, bool isSolid, bool genCollisions, float mass);
[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
public static extern bool SetObjectBuoyancy(uint worldID, uint id, float buoyancy);
[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
public static extern bool HasObject(uint worldID, uint id);
[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
public static extern bool DestroyObject(uint worldID, uint id);
[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
public static extern SweepHit ConvexSweepTest(uint worldID, uint id, Vector3 to, float extraMargin);
[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
public static extern RaycastHit RayTest(uint worldID, uint id, Vector3 from, Vector3 to);
[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
public static extern Vector3 RecoverFromPenetration(uint worldID, uint id);
// Log a debug message
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
public delegate void DebugLogCallback([MarshalAs(UnmanagedType.LPStr)]string msg);
[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
public static extern void SetDebugLogCallback(DebugLogCallback callback);
}
}

View File

@ -0,0 +1,341 @@
/* The MIT License
*
* Copyright (c) 2010 Intel Corporation.
* All rights reserved.
*
* Based on the convexdecomposition library from
* <http://codesuppository.googlecode.com> by John W. Ratcliff and Stan Melax.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
using System;
using System.Collections.Generic;
namespace OpenSim.Region.Physics.ConvexDecompositionDotNet
{
public class Wpoint
{
public float3 mPoint;
public float mWeight;
public Wpoint(float3 p, float w)
{
mPoint = p;
mWeight = w;
}
}
public class CTri
{
private const int WSCALE = 4;
public float3 mP1;
public float3 mP2;
public float3 mP3;
public float3 mNear1;
public float3 mNear2;
public float3 mNear3;
public float3 mNormal;
public float mPlaneD;
public float mConcavity;
public float mC1;
public float mC2;
public float mC3;
public int mI1;
public int mI2;
public int mI3;
public int mProcessed; // already been added...
public CTri(float3 p1, float3 p2, float3 p3, int i1, int i2, int i3)
{
mProcessed = 0;
mI1 = i1;
mI2 = i2;
mI3 = i3;
mP1 = new float3(p1);
mP2 = new float3(p2);
mP3 = new float3(p3);
mNear1 = new float3();
mNear2 = new float3();
mNear3 = new float3();
mNormal = new float3();
mPlaneD = mNormal.ComputePlane(mP1, mP2, mP3);
}
public float Facing(CTri t)
{
return float3.dot(mNormal, t.mNormal);
}
public bool clip(float3 start, ref float3 end)
{
float3 sect = new float3();
bool hit = lineIntersectsTriangle(start, end, mP1, mP2, mP3, ref sect);
if (hit)
end = sect;
return hit;
}
public bool Concave(float3 p, ref float distance, ref float3 n)
{
n.NearestPointInTriangle(p, mP1, mP2, mP3);
distance = p.Distance(n);
return true;
}
public void addTri(int[] indices, int i1, int i2, int i3, ref int tcount)
{
indices[tcount * 3 + 0] = i1;
indices[tcount * 3 + 1] = i2;
indices[tcount * 3 + 2] = i3;
tcount++;
}
public float getVolume()
{
int[] indices = new int[8 * 3];
int tcount = 0;
addTri(indices, 0, 1, 2, ref tcount);
addTri(indices, 3, 4, 5, ref tcount);
addTri(indices, 0, 3, 4, ref tcount);
addTri(indices, 0, 4, 1, ref tcount);
addTri(indices, 1, 4, 5, ref tcount);
addTri(indices, 1, 5, 2, ref tcount);
addTri(indices, 0, 3, 5, ref tcount);
addTri(indices, 0, 5, 2, ref tcount);
List<float3> vertices = new List<float3> { mP1, mP2, mP3, mNear1, mNear2, mNear3 };
List<int> indexList = new List<int>(indices);
float v = Concavity.computeMeshVolume(vertices, indexList);
return v;
}
public float raySect(float3 p, float3 dir, ref float3 sect)
{
float4 plane = new float4();
plane.x = mNormal.x;
plane.y = mNormal.y;
plane.z = mNormal.z;
plane.w = mPlaneD;
float3 dest = p + dir * 100000f;
intersect(p, dest, ref sect, plane);
return sect.Distance(p); // return the intersection distance
}
public float planeDistance(float3 p)
{
float4 plane = new float4();
plane.x = mNormal.x;
plane.y = mNormal.y;
plane.z = mNormal.z;
plane.w = mPlaneD;
return DistToPt(p, plane);
}
public bool samePlane(CTri t)
{
const float THRESH = 0.001f;
float dd = Math.Abs(t.mPlaneD - mPlaneD);
if (dd > THRESH)
return false;
dd = Math.Abs(t.mNormal.x - mNormal.x);
if (dd > THRESH)
return false;
dd = Math.Abs(t.mNormal.y - mNormal.y);
if (dd > THRESH)
return false;
dd = Math.Abs(t.mNormal.z - mNormal.z);
if (dd > THRESH)
return false;
return true;
}
public bool hasIndex(int i)
{
if (i == mI1 || i == mI2 || i == mI3)
return true;
return false;
}
public bool sharesEdge(CTri t)
{
bool ret = false;
uint count = 0;
if (t.hasIndex(mI1))
count++;
if (t.hasIndex(mI2))
count++;
if (t.hasIndex(mI3))
count++;
if (count >= 2)
ret = true;
return ret;
}
public float area()
{
float a = mConcavity * mP1.Area(mP2, mP3);
return a;
}
public void addWeighted(List<Wpoint> list)
{
Wpoint p1 = new Wpoint(mP1, mC1);
Wpoint p2 = new Wpoint(mP2, mC2);
Wpoint p3 = new Wpoint(mP3, mC3);
float3 d1 = mNear1 - mP1;
float3 d2 = mNear2 - mP2;
float3 d3 = mNear3 - mP3;
d1 *= WSCALE;
d2 *= WSCALE;
d3 *= WSCALE;
d1 = d1 + mP1;
d2 = d2 + mP2;
d3 = d3 + mP3;
Wpoint p4 = new Wpoint(d1, mC1);
Wpoint p5 = new Wpoint(d2, mC2);
Wpoint p6 = new Wpoint(d3, mC3);
list.Add(p1);
list.Add(p2);
list.Add(p3);
list.Add(p4);
list.Add(p5);
list.Add(p6);
}
private static float DistToPt(float3 p, float4 plane)
{
float x = p.x;
float y = p.y;
float z = p.z;
float d = x*plane.x + y*plane.y + z*plane.z + plane.w;
return d;
}
private static void intersect(float3 p1, float3 p2, ref float3 split, float4 plane)
{
float dp1 = DistToPt(p1, plane);
float3 dir = new float3();
dir.x = p2[0] - p1[0];
dir.y = p2[1] - p1[1];
dir.z = p2[2] - p1[2];
float dot1 = dir[0] * plane[0] + dir[1] * plane[1] + dir[2] * plane[2];
float dot2 = dp1 - plane[3];
float t = -(plane[3] + dot2) / dot1;
split.x = (dir[0] * t) + p1[0];
split.y = (dir[1] * t) + p1[1];
split.z = (dir[2] * t) + p1[2];
}
private static bool rayIntersectsTriangle(float3 p, float3 d, float3 v0, float3 v1, float3 v2, out float t)
{
t = 0f;
float3 e1, e2, h, s, q;
float a, f, u, v;
e1 = v1 - v0;
e2 = v2 - v0;
h = float3.cross(d, e2);
a = float3.dot(e1, h);
if (a > -0.00001f && a < 0.00001f)
return false;
f = 1f / a;
s = p - v0;
u = f * float3.dot(s, h);
if (u < 0.0f || u > 1.0f)
return false;
q = float3.cross(s, e1);
v = f * float3.dot(d, q);
if (v < 0.0f || u + v > 1.0f)
return false;
// at this stage we can compute t to find out where
// the intersection point is on the line
t = f * float3.dot(e2, q);
if (t > 0f) // ray intersection
return true;
else // this means that there is a line intersection but not a ray intersection
return false;
}
private static bool lineIntersectsTriangle(float3 rayStart, float3 rayEnd, float3 p1, float3 p2, float3 p3, ref float3 sect)
{
float3 dir = rayEnd - rayStart;
float d = (float)Math.Sqrt(dir[0] * dir[0] + dir[1] * dir[1] + dir[2] * dir[2]);
float r = 1.0f / d;
dir *= r;
float t;
bool ret = rayIntersectsTriangle(rayStart, dir, p1, p2, p3, out t);
if (ret)
{
if (t > d)
{
sect.x = rayStart.x + dir.x * t;
sect.y = rayStart.y + dir.y * t;
sect.z = rayStart.z + dir.z * t;
}
else
{
ret = false;
}
}
return ret;
}
}
}

View File

@ -0,0 +1,233 @@
/* The MIT License
*
* Copyright (c) 2010 Intel Corporation.
* All rights reserved.
*
* Based on the convexdecomposition library from
* <http://codesuppository.googlecode.com> by John W. Ratcliff and Stan Melax.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
using System;
using System.Collections.Generic;
using System.Text;
namespace OpenSim.Region.Physics.ConvexDecompositionDotNet
{
public static class Concavity
{
// compute's how 'concave' this object is and returns the total volume of the
// convex hull as well as the volume of the 'concavity' which was found.
public static float computeConcavity(List<float3> vertices, List<int> indices, ref float4 plane, ref float volume)
{
float cret = 0f;
volume = 1f;
HullResult result = new HullResult();
HullDesc desc = new HullDesc();
desc.MaxFaces = 256;
desc.MaxVertices = 256;
desc.SetHullFlag(HullFlag.QF_TRIANGLES);
desc.Vertices = vertices;
HullError ret = HullUtils.CreateConvexHull(desc, ref result);
if (ret == HullError.QE_OK)
{
volume = computeMeshVolume2(result.OutputVertices, result.Indices);
// ok..now..for each triangle on the original mesh..
// we extrude the points to the nearest point on the hull.
List<CTri> tris = new List<CTri>();
for (int i = 0; i < result.Indices.Count / 3; i++)
{
int i1 = result.Indices[i * 3 + 0];
int i2 = result.Indices[i * 3 + 1];
int i3 = result.Indices[i * 3 + 2];
float3 p1 = result.OutputVertices[i1];
float3 p2 = result.OutputVertices[i2];
float3 p3 = result.OutputVertices[i3];
CTri t = new CTri(p1, p2, p3, i1, i2, i3);
tris.Add(t);
}
// we have not pre-computed the plane equation for each triangle in the convex hull..
float totalVolume = 0;
List<CTri> ftris = new List<CTri>(); // 'feature' triangles.
List<CTri> input_mesh = new List<CTri>();
for (int i = 0; i < indices.Count / 3; i++)
{
int i1 = indices[i * 3 + 0];
int i2 = indices[i * 3 + 1];
int i3 = indices[i * 3 + 2];
float3 p1 = vertices[i1];
float3 p2 = vertices[i2];
float3 p3 = vertices[i3];
CTri t = new CTri(p1, p2, p3, i1, i2, i3);
input_mesh.Add(t);
}
for (int i = 0; i < indices.Count / 3; i++)
{
int i1 = indices[i * 3 + 0];
int i2 = indices[i * 3 + 1];
int i3 = indices[i * 3 + 2];
float3 p1 = vertices[i1];
float3 p2 = vertices[i2];
float3 p3 = vertices[i3];
CTri t = new CTri(p1, p2, p3, i1, i2, i3);
featureMatch(t, tris, input_mesh);
if (t.mConcavity > 0.05f)
{
float v = t.getVolume();
totalVolume += v;
ftris.Add(t);
}
}
SplitPlane.computeSplitPlane(vertices, indices, ref plane);
cret = totalVolume;
}
return cret;
}
public static bool featureMatch(CTri m, List<CTri> tris, List<CTri> input_mesh)
{
bool ret = false;
float neardot = 0.707f;
m.mConcavity = 0;
for (int i = 0; i < tris.Count; i++)
{
CTri t = tris[i];
if (t.samePlane(m))
{
ret = false;
break;
}
float dot = float3.dot(t.mNormal, m.mNormal);
if (dot > neardot)
{
float d1 = t.planeDistance(m.mP1);
float d2 = t.planeDistance(m.mP2);
float d3 = t.planeDistance(m.mP3);
if (d1 > 0.001f || d2 > 0.001f || d3 > 0.001f) // can't be near coplaner!
{
neardot = dot;
t.raySect(m.mP1, m.mNormal, ref m.mNear1);
t.raySect(m.mP2, m.mNormal, ref m.mNear2);
t.raySect(m.mP3, m.mNormal, ref m.mNear3);
ret = true;
}
}
}
if (ret)
{
m.mC1 = m.mP1.Distance(m.mNear1);
m.mC2 = m.mP2.Distance(m.mNear2);
m.mC3 = m.mP3.Distance(m.mNear3);
m.mConcavity = m.mC1;
if (m.mC2 > m.mConcavity)
m.mConcavity = m.mC2;
if (m.mC3 > m.mConcavity)
m.mConcavity = m.mC3;
}
return ret;
}
private static float det(float3 p1, float3 p2, float3 p3)
{
return p1.x * p2.y * p3.z + p2.x * p3.y * p1.z + p3.x * p1.y * p2.z - p1.x * p3.y * p2.z - p2.x * p1.y * p3.z - p3.x * p2.y * p1.z;
}
public static float computeMeshVolume(List<float3> vertices, List<int> indices)
{
float volume = 0f;
for (int i = 0; i < indices.Count / 3; i++)
{
float3 p1 = vertices[indices[i * 3 + 0]];
float3 p2 = vertices[indices[i * 3 + 1]];
float3 p3 = vertices[indices[i * 3 + 2]];
volume += det(p1, p2, p3); // compute the volume of the tetrahedran relative to the origin.
}
volume *= (1.0f / 6.0f);
if (volume < 0f)
return -volume;
return volume;
}
public static float computeMeshVolume2(List<float3> vertices, List<int> indices)
{
float volume = 0f;
float3 p0 = vertices[0];
for (int i = 0; i < indices.Count / 3; i++)
{
float3 p1 = vertices[indices[i * 3 + 0]];
float3 p2 = vertices[indices[i * 3 + 1]];
float3 p3 = vertices[indices[i * 3 + 2]];
volume += tetVolume(p0, p1, p2, p3); // compute the volume of the tetrahedron relative to the root vertice
}
return volume * (1.0f / 6.0f);
}
private static float tetVolume(float3 p0, float3 p1, float3 p2, float3 p3)
{
float3 a = p1 - p0;
float3 b = p2 - p0;
float3 c = p3 - p0;
float3 cross = float3.cross(b, c);
float volume = float3.dot(a, cross);
if (volume < 0f)
return -volume;
return volume;
}
}
}

View File

@ -0,0 +1,411 @@
/* The MIT License
*
* Copyright (c) 2010 Intel Corporation.
* All rights reserved.
*
* Based on the convexdecomposition library from
* <http://codesuppository.googlecode.com> by John W. Ratcliff and Stan Melax.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
using System;
using System.Collections.Generic;
using System.Diagnostics;
namespace OpenSim.Region.Physics.ConvexDecompositionDotNet
{
public class DecompDesc
{
public List<float3> mVertices;
public List<int> mIndices;
// options
public uint mDepth; // depth to split, a maximum of 10, generally not over 7.
public float mCpercent; // the concavity threshold percentage. 0=20 is reasonable.
public float mPpercent; // the percentage volume conservation threshold to collapse hulls. 0-30 is reasonable.
// hull output limits.
public uint mMaxVertices; // maximum number of vertices in the output hull. Recommended 32 or less.
public float mSkinWidth; // a skin width to apply to the output hulls.
public ConvexDecompositionCallback mCallback; // the interface to receive back the results.
public DecompDesc()
{
mDepth = 5;
mCpercent = 5;
mPpercent = 5;
mMaxVertices = 32;
}
}
public class CHull
{
public float[] mMin = new float[3];
public float[] mMax = new float[3];
public float mVolume;
public float mDiagonal;
public ConvexResult mResult;
public CHull(ConvexResult result)
{
mResult = new ConvexResult(result);
mVolume = Concavity.computeMeshVolume(result.HullVertices, result.HullIndices);
mDiagonal = getBoundingRegion(result.HullVertices, mMin, mMax);
float dx = mMax[0] - mMin[0];
float dy = mMax[1] - mMin[1];
float dz = mMax[2] - mMin[2];
dx *= 0.1f; // inflate 1/10th on each edge
dy *= 0.1f; // inflate 1/10th on each edge
dz *= 0.1f; // inflate 1/10th on each edge
mMin[0] -= dx;
mMin[1] -= dy;
mMin[2] -= dz;
mMax[0] += dx;
mMax[1] += dy;
mMax[2] += dz;
}
public void Dispose()
{
mResult = null;
}
public bool overlap(CHull h)
{
return overlapAABB(mMin, mMax, h.mMin, h.mMax);
}
// returns the d1Giagonal distance
private static float getBoundingRegion(List<float3> points, float[] bmin, float[] bmax)
{
float3 first = points[0];
bmin[0] = first.x;
bmin[1] = first.y;
bmin[2] = first.z;
bmax[0] = first.x;
bmax[1] = first.y;
bmax[2] = first.z;
for (int i = 1; i < points.Count; i++)
{
float3 p = points[i];
if (p[0] < bmin[0]) bmin[0] = p[0];
if (p[1] < bmin[1]) bmin[1] = p[1];
if (p[2] < bmin[2]) bmin[2] = p[2];
if (p[0] > bmax[0]) bmax[0] = p[0];
if (p[1] > bmax[1]) bmax[1] = p[1];
if (p[2] > bmax[2]) bmax[2] = p[2];
}
float dx = bmax[0] - bmin[0];
float dy = bmax[1] - bmin[1];
float dz = bmax[2] - bmin[2];
return (float)Math.Sqrt(dx * dx + dy * dy + dz * dz);
}
// return true if the two AABB's overlap.
private static bool overlapAABB(float[] bmin1, float[] bmax1, float[] bmin2, float[] bmax2)
{
if (bmax2[0] < bmin1[0]) return false; // if the maximum is less than our minimum on any axis
if (bmax2[1] < bmin1[1]) return false;
if (bmax2[2] < bmin1[2]) return false;
if (bmin2[0] > bmax1[0]) return false; // if the minimum is greater than our maximum on any axis
if (bmin2[1] > bmax1[1]) return false; // if the minimum is greater than our maximum on any axis
if (bmin2[2] > bmax1[2]) return false; // if the minimum is greater than our maximum on any axis
return true; // the extents overlap
}
}
public class ConvexBuilder
{
public List<CHull> mChulls = new List<CHull>();
private ConvexDecompositionCallback mCallback;
private int MAXDEPTH = 8;
private float CONCAVE_PERCENT = 1f;
private float MERGE_PERCENT = 2f;
public ConvexBuilder(ConvexDecompositionCallback callback)
{
mCallback = callback;
}
public void Dispose()
{
int i;
for (i = 0; i < mChulls.Count; i++)
{
CHull cr = mChulls[i];
cr.Dispose();
}
}
public bool isDuplicate(uint i1, uint i2, uint i3, uint ci1, uint ci2, uint ci3)
{
uint dcount = 0;
Debug.Assert(i1 != i2 && i1 != i3 && i2 != i3);
Debug.Assert(ci1 != ci2 && ci1 != ci3 && ci2 != ci3);
if (i1 == ci1 || i1 == ci2 || i1 == ci3)
dcount++;
if (i2 == ci1 || i2 == ci2 || i2 == ci3)
dcount++;
if (i3 == ci1 || i3 == ci2 || i3 == ci3)
dcount++;
return dcount == 3;
}
public void getMesh(ConvexResult cr, VertexPool vc, List<int> indices)
{
List<int> src = cr.HullIndices;
for (int i = 0; i < src.Count / 3; i++)
{
int i1 = src[i * 3 + 0];
int i2 = src[i * 3 + 1];
int i3 = src[i * 3 + 2];
float3 p1 = cr.HullVertices[i1];
float3 p2 = cr.HullVertices[i2];
float3 p3 = cr.HullVertices[i3];
i1 = vc.getIndex(p1);
i2 = vc.getIndex(p2);
i3 = vc.getIndex(p3);
}
}
public CHull canMerge(CHull a, CHull b)
{
if (!a.overlap(b)) // if their AABB's (with a little slop) don't overlap, then return.
return null;
CHull ret = null;
// ok..we are going to combine both meshes into a single mesh
// and then we are going to compute the concavity...
VertexPool vc = new VertexPool();
List<int> indices = new List<int>();
getMesh(a.mResult, vc, indices);
getMesh(b.mResult, vc, indices);
int vcount = vc.GetSize();
List<float3> vertices = vc.GetVertices();
int tcount = indices.Count / 3;
//don't do anything if hull is empty
if (tcount == 0)
{
vc.Clear();
return null;
}
HullResult hresult = new HullResult();
HullDesc desc = new HullDesc();
desc.SetHullFlag(HullFlag.QF_TRIANGLES);
desc.Vertices = vertices;
HullError hret = HullUtils.CreateConvexHull(desc, ref hresult);
if (hret == HullError.QE_OK)
{
float combineVolume = Concavity.computeMeshVolume(hresult.OutputVertices, hresult.Indices);
float sumVolume = a.mVolume + b.mVolume;
float percent = (sumVolume * 100) / combineVolume;
if (percent >= (100.0f - MERGE_PERCENT))
{
ConvexResult cr = new ConvexResult(hresult.OutputVertices, hresult.Indices);
ret = new CHull(cr);
}
}
vc.Clear();
return ret;
}
public bool combineHulls()
{
bool combine = false;
sortChulls(mChulls); // sort the convex hulls, largest volume to least...
List<CHull> output = new List<CHull>(); // the output hulls...
int i;
for (i = 0; i < mChulls.Count && !combine; ++i)
{
CHull cr = mChulls[i];
int j;
for (j = 0; j < mChulls.Count; j++)
{
CHull match = mChulls[j];
if (cr != match) // don't try to merge a hull with itself, that be stoopid
{
CHull merge = canMerge(cr, match); // if we can merge these two....
if (merge != null)
{
output.Add(merge);
++i;
while (i != mChulls.Count)
{
CHull cr2 = mChulls[i];
if (cr2 != match)
{
output.Add(cr2);
}
i++;
}
cr.Dispose();
match.Dispose();
combine = true;
break;
}
}
}
if (combine)
{
break;
}
else
{
output.Add(cr);
}
}
if (combine)
{
mChulls.Clear();
mChulls = output;
output.Clear();
}
return combine;
}
public int process(DecompDesc desc)
{
int ret = 0;
MAXDEPTH = (int)desc.mDepth;
CONCAVE_PERCENT = desc.mCpercent;
MERGE_PERCENT = desc.mPpercent;
ConvexDecomposition.calcConvexDecomposition(desc.mVertices, desc.mIndices, ConvexDecompResult, 0f, 0, MAXDEPTH, CONCAVE_PERCENT, MERGE_PERCENT);
while (combineHulls()) // keep combinging hulls until I can't combine any more...
;
int i;
for (i = 0; i < mChulls.Count; i++)
{
CHull cr = mChulls[i];
// before we hand it back to the application, we need to regenerate the hull based on the
// limits given by the user.
ConvexResult c = cr.mResult; // the high resolution hull...
HullResult result = new HullResult();
HullDesc hdesc = new HullDesc();
hdesc.SetHullFlag(HullFlag.QF_TRIANGLES);
hdesc.Vertices = c.HullVertices;
hdesc.MaxVertices = desc.mMaxVertices; // maximum number of vertices allowed in the output
if (desc.mSkinWidth != 0f)
{
hdesc.SkinWidth = desc.mSkinWidth;
hdesc.SetHullFlag(HullFlag.QF_SKIN_WIDTH); // do skin width computation.
}
HullError ret2 = HullUtils.CreateConvexHull(hdesc, ref result);
if (ret2 == HullError.QE_OK)
{
ConvexResult r = new ConvexResult(result.OutputVertices, result.Indices);
r.mHullVolume = Concavity.computeMeshVolume(result.OutputVertices, result.Indices); // the volume of the hull.
// compute the best fit OBB
//computeBestFitOBB(result.mNumOutputVertices, result.mOutputVertices, sizeof(float) * 3, r.mOBBSides, r.mOBBTransform);
//r.mOBBVolume = r.mOBBSides[0] * r.mOBBSides[1] * r.mOBBSides[2]; // compute the OBB volume.
//fm_getTranslation(r.mOBBTransform, r.mOBBCenter); // get the translation component of the 4x4 matrix.
//fm_matrixToQuat(r.mOBBTransform, r.mOBBOrientation); // extract the orientation as a quaternion.
//r.mSphereRadius = computeBoundingSphere(result.mNumOutputVertices, result.mOutputVertices, r.mSphereCenter);
//r.mSphereVolume = fm_sphereVolume(r.mSphereRadius);
mCallback(r);
}
result = null;
cr.Dispose();
}
ret = mChulls.Count;
mChulls.Clear();
return ret;
}
public void ConvexDecompResult(ConvexResult result)
{
CHull ch = new CHull(result);
mChulls.Add(ch);
}
public void sortChulls(List<CHull> hulls)
{
hulls.Sort(delegate(CHull a, CHull b) { return a.mVolume.CompareTo(b.mVolume); });
}
}
}

View File

@ -0,0 +1,200 @@
/* The MIT License
*
* Copyright (c) 2010 Intel Corporation.
* All rights reserved.
*
* Based on the convexdecomposition library from
* <http://codesuppository.googlecode.com> by John W. Ratcliff and Stan Melax.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
using System;
using System.Collections.Generic;
using System.Diagnostics;
namespace OpenSim.Region.Physics.ConvexDecompositionDotNet
{
public delegate void ConvexDecompositionCallback(ConvexResult result);
public class FaceTri
{
public float3 P1;
public float3 P2;
public float3 P3;
public FaceTri() { }
public FaceTri(List<float3> vertices, int i1, int i2, int i3)
{
P1 = new float3(vertices[i1]);
P2 = new float3(vertices[i2]);
P3 = new float3(vertices[i3]);
}
}
public static class ConvexDecomposition
{
private static void addTri(VertexPool vl, List<int> list, float3 p1, float3 p2, float3 p3)
{
int i1 = vl.getIndex(p1);
int i2 = vl.getIndex(p2);
int i3 = vl.getIndex(p3);
// do *not* process degenerate triangles!
if ( i1 != i2 && i1 != i3 && i2 != i3 )
{
list.Add(i1);
list.Add(i2);
list.Add(i3);
}
}
public static void calcConvexDecomposition(List<float3> vertices, List<int> indices, ConvexDecompositionCallback callback, float masterVolume, int depth,
int maxDepth, float concavePercent, float mergePercent)
{
float4 plane = new float4();
bool split = false;
if (depth < maxDepth)
{
float volume = 0f;
float c = Concavity.computeConcavity(vertices, indices, ref plane, ref volume);
if (depth == 0)
{
masterVolume = volume;
}
float percent = (c * 100.0f) / masterVolume;
if (percent > concavePercent) // if great than 5% of the total volume is concave, go ahead and keep splitting.
{
split = true;
}
}
if (depth >= maxDepth || !split)
{
HullResult result = new HullResult();
HullDesc desc = new HullDesc();
desc.SetHullFlag(HullFlag.QF_TRIANGLES);
desc.Vertices = vertices;
HullError ret = HullUtils.CreateConvexHull(desc, ref result);
if (ret == HullError.QE_OK)
{
ConvexResult r = new ConvexResult(result.OutputVertices, result.Indices);
callback(r);
}
return;
}
List<int> ifront = new List<int>();
List<int> iback = new List<int>();
VertexPool vfront = new VertexPool();
VertexPool vback = new VertexPool();
// ok..now we are going to 'split' all of the input triangles against this plane!
for (int i = 0; i < indices.Count / 3; i++)
{
int i1 = indices[i * 3 + 0];
int i2 = indices[i * 3 + 1];
int i3 = indices[i * 3 + 2];
FaceTri t = new FaceTri(vertices, i1, i2, i3);
float3[] front = new float3[4];
float3[] back = new float3[4];
int fcount = 0;
int bcount = 0;
PlaneTriResult result = PlaneTri.planeTriIntersection(plane, t, 0.00001f, ref front, out fcount, ref back, out bcount);
if (fcount > 4 || bcount > 4)
{
result = PlaneTri.planeTriIntersection(plane, t, 0.00001f, ref front, out fcount, ref back, out bcount);
}
switch (result)
{
case PlaneTriResult.PTR_FRONT:
Debug.Assert(fcount == 3);
addTri(vfront, ifront, front[0], front[1], front[2]);
break;
case PlaneTriResult.PTR_BACK:
Debug.Assert(bcount == 3);
addTri(vback, iback, back[0], back[1], back[2]);
break;
case PlaneTriResult.PTR_SPLIT:
Debug.Assert(fcount >= 3 && fcount <= 4);
Debug.Assert(bcount >= 3 && bcount <= 4);
addTri(vfront, ifront, front[0], front[1], front[2]);
addTri(vback, iback, back[0], back[1], back[2]);
if (fcount == 4)
{
addTri(vfront, ifront, front[0], front[2], front[3]);
}
if (bcount == 4)
{
addTri(vback, iback, back[0], back[2], back[3]);
}
break;
}
}
// ok... here we recursively call
if (ifront.Count > 0)
{
int vcount = vfront.GetSize();
List<float3> vertices2 = vfront.GetVertices();
for (int i = 0; i < vertices2.Count; i++)
vertices2[i] = new float3(vertices2[i]);
int tcount = ifront.Count / 3;
calcConvexDecomposition(vertices2, ifront, callback, masterVolume, depth + 1, maxDepth, concavePercent, mergePercent);
}
ifront.Clear();
vfront.Clear();
if (iback.Count > 0)
{
int vcount = vback.GetSize();
List<float3> vertices2 = vback.GetVertices();
int tcount = iback.Count / 3;
calcConvexDecomposition(vertices2, iback, callback, masterVolume, depth + 1, maxDepth, concavePercent, mergePercent);
}
iback.Clear();
vback.Clear();
}
}
}

View File

@ -0,0 +1,74 @@
/* The MIT License
*
* Copyright (c) 2010 Intel Corporation.
* All rights reserved.
*
* Based on the convexdecomposition library from
* <http://codesuppository.googlecode.com> by John W. Ratcliff and Stan Melax.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
using System;
using System.Collections.Generic;
namespace OpenSim.Region.Physics.ConvexDecompositionDotNet
{
public class ConvexResult
{
public List<float3> HullVertices;
public List<int> HullIndices;
public float mHullVolume; // the volume of the convex hull.
//public float[] OBBSides = new float[3]; // the width, height and breadth of the best fit OBB
//public float[] OBBCenter = new float[3]; // the center of the OBB
//public float[] OBBOrientation = new float[4]; // the quaternion rotation of the OBB.
//public float[] OBBTransform = new float[16]; // the 4x4 transform of the OBB.
//public float OBBVolume; // the volume of the OBB
//public float SphereRadius; // radius and center of best fit sphere
//public float[] SphereCenter = new float[3];
//public float SphereVolume; // volume of the best fit sphere
public ConvexResult()
{
HullVertices = new List<float3>();
HullIndices = new List<int>();
}
public ConvexResult(List<float3> hvertices, List<int> hindices)
{
HullVertices = hvertices;
HullIndices = hindices;
}
public ConvexResult(ConvexResult r)
{
HullVertices = new List<float3>(r.HullVertices);
HullIndices = new List<int>(r.HullIndices);
}
public void Dispose()
{
HullVertices = null;
HullIndices = null;
}
}
}

View File

@ -0,0 +1,171 @@
/* The MIT License
*
* Copyright (c) 2010 Intel Corporation.
* All rights reserved.
*
* Based on the convexdecomposition library from
* <http://codesuppository.googlecode.com> by John W. Ratcliff and Stan Melax.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
using System;
using System.Collections.Generic;
namespace OpenSim.Region.Physics.ConvexDecompositionDotNet
{
public class HullResult
{
public bool Polygons = true; // true if indices represents polygons, false indices are triangles
public List<float3> OutputVertices = new List<float3>();
public List<int> Indices;
// If triangles, then indices are array indexes into the vertex list.
// If polygons, indices are in the form (number of points in face) (p1, p2, p3, ..) etc..
}
public class PHullResult
{
public List<float3> Vertices = new List<float3>();
public List<int> Indices = new List<int>();
}
[Flags]
public enum HullFlag : int
{
QF_DEFAULT = 0,
QF_TRIANGLES = (1 << 0), // report results as triangles, not polygons.
QF_SKIN_WIDTH = (1 << 2) // extrude hull based on this skin width
}
public enum HullError : int
{
QE_OK, // success!
QE_FAIL // failed.
}
public class HullDesc
{
public HullFlag Flags; // flags to use when generating the convex hull.
public List<float3> Vertices;
public float NormalEpsilon; // the epsilon for removing duplicates. This is a normalized value, if normalized bit is on.
public float SkinWidth;
public uint MaxVertices; // maximum number of vertices to be considered for the hull!
public uint MaxFaces;
public HullDesc()
{
Flags = HullFlag.QF_DEFAULT;
Vertices = new List<float3>();
NormalEpsilon = 0.001f;
MaxVertices = 4096;
MaxFaces = 4096;
SkinWidth = 0.01f;
}
public HullDesc(HullFlag flags, List<float3> vertices)
{
Flags = flags;
Vertices = new List<float3>(vertices);
NormalEpsilon = 0.001f;
MaxVertices = 4096;
MaxFaces = 4096;
SkinWidth = 0.01f;
}
public bool HasHullFlag(HullFlag flag)
{
return (Flags & flag) != 0;
}
public void SetHullFlag(HullFlag flag)
{
Flags |= flag;
}
public void ClearHullFlag(HullFlag flag)
{
Flags &= ~flag;
}
}
public class ConvexH
{
public struct HalfEdge
{
public short ea; // the other half of the edge (index into edges list)
public byte v; // the vertex at the start of this edge (index into vertices list)
public byte p; // the facet on which this edge lies (index into facets list)
public HalfEdge(short _ea, byte _v, byte _p)
{
ea = _ea;
v = _v;
p = _p;
}
public HalfEdge(HalfEdge e)
{
ea = e.ea;
v = e.v;
p = e.p;
}
}
public List<float3> vertices = new List<float3>();
public List<HalfEdge> edges = new List<HalfEdge>();
public List<Plane> facets = new List<Plane>();
public ConvexH(int vertices_size, int edges_size, int facets_size)
{
vertices = new List<float3>(vertices_size);
edges = new List<HalfEdge>(edges_size);
facets = new List<Plane>(facets_size);
}
}
public class VertFlag
{
public byte planetest;
public byte junk;
public byte undermap;
public byte overmap;
}
public class EdgeFlag
{
public byte planetest;
public byte fixes;
public short undermap;
public short overmap;
}
public class PlaneFlag
{
public byte undermap;
public byte overmap;
}
public class Coplanar
{
public ushort ea;
public byte v0;
public byte v1;
}
}

View File

@ -0,0 +1,99 @@
/* The MIT License
*
* Copyright (c) 2010 Intel Corporation.
* All rights reserved.
*
* Based on the convexdecomposition library from
* <http://codesuppository.googlecode.com> by John W. Ratcliff and Stan Melax.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
using System;
using System.Collections.Generic;
using System.Diagnostics;
namespace OpenSim.Region.Physics.ConvexDecompositionDotNet
{
public class HullTriangle : int3
{
public int3 n = new int3();
public int id;
public int vmax;
public float rise;
private List<HullTriangle> tris;
public HullTriangle(int a, int b, int c, List<HullTriangle> tris)
: base(a, b, c)
{
this.tris = tris;
n = new int3(-1, -1, -1);
id = tris.Count;
tris.Add(this);
vmax = -1;
rise = 0.0f;
}
public void Dispose()
{
Debug.Assert(tris[id] == this);
tris[id] = null;
}
public int neib(int a, int b)
{
int i;
for (i = 0; i < 3; i++)
{
int i1 = (i + 1) % 3;
int i2 = (i + 2) % 3;
if ((this)[i] == a && (this)[i1] == b)
return n[i2];
if ((this)[i] == b && (this)[i1] == a)
return n[i2];
}
Debug.Assert(false);
return -1;
}
public void setneib(int a, int b, int value)
{
int i;
for (i = 0; i < 3; i++)
{
int i1 = (i + 1) % 3;
int i2 = (i + 2) % 3;
if ((this)[i] == a && (this)[i1] == b)
{
n[i2] = value;
return;
}
if ((this)[i] == b && (this)[i1] == a)
{
n[i2] = value;
return;
}
}
}
}
}

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,28 @@
ConvexDecompositionDotNet
-------------------------
The MIT License
Copyright (c) 2010 Intel Corporation.
All rights reserved.
Based on the convexdecomposition library from
<http://codesuppository.googlecode.com> by John W. Ratcliff and Stan Melax.
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.

View File

@ -0,0 +1,99 @@
/* The MIT License
*
* Copyright (c) 2010 Intel Corporation.
* All rights reserved.
*
* Based on the convexdecomposition library from
* <http://codesuppository.googlecode.com> by John W. Ratcliff and Stan Melax.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
using System;
namespace OpenSim.Region.Physics.ConvexDecompositionDotNet
{
public class Plane
{
public float3 normal = new float3();
public float dist; // distance below origin - the D from plane equasion Ax+By+Cz+D=0
public Plane(float3 n, float d)
{
normal = new float3(n);
dist = d;
}
public Plane(Plane p)
{
normal = new float3(p.normal);
dist = p.dist;
}
public Plane()
{
dist = 0;
}
public void Transform(float3 position, Quaternion orientation)
{
// Transforms the plane to the space defined by the
// given position/orientation
float3 newNormal = Quaternion.Inverse(orientation) * normal;
float3 origin = Quaternion.Inverse(orientation) * (-normal * dist - position);
normal = newNormal;
dist = -float3.dot(newNormal, origin);
}
public override int GetHashCode()
{
return normal.GetHashCode() ^ dist.GetHashCode();
}
public override bool Equals(object obj)
{
Plane p = obj as Plane;
if (p == null)
return false;
return this == p;
}
public static bool operator ==(Plane a, Plane b)
{
return (a.normal == b.normal && a.dist == b.dist);
}
public static bool operator !=(Plane a, Plane b)
{
return !(a == b);
}
public static Plane PlaneFlip(Plane plane)
{
return new Plane(-plane.normal, -plane.dist);
}
public static bool coplanar(Plane a, Plane b)
{
return (a == b || a == PlaneFlip(b));
}
}
}

View File

@ -0,0 +1,211 @@
/* The MIT License
*
* Copyright (c) 2010 Intel Corporation.
* All rights reserved.
*
* Based on the convexdecomposition library from
* <http://codesuppository.googlecode.com> by John W. Ratcliff and Stan Melax.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
using System;
using System.Collections.Generic;
using System.Diagnostics;
namespace OpenSim.Region.Physics.ConvexDecompositionDotNet
{
public enum PlaneTriResult : int
{
PTR_FRONT,
PTR_BACK,
PTR_SPLIT
}
public static class PlaneTri
{
private static float DistToPt(float3 p, float4 plane)
{
return p.x * plane.x + p.y * plane.y + p.z * plane.z + plane.w;
}
private static PlaneTriResult getSidePlane(float3 p, float4 plane, float epsilon)
{
float d = DistToPt(p, plane);
if ((d + epsilon) > 0f)
return PlaneTriResult.PTR_FRONT; // it is 'in front' within the provided epsilon value.
return PlaneTriResult.PTR_BACK;
}
private static void add(float3 p, float3[] dest, ref int pcount)
{
dest[pcount++] = new float3(p);
Debug.Assert(pcount <= 4);
}
// assumes that the points are on opposite sides of the plane!
private static void intersect(float3 p1, float3 p2, float3 split, float4 plane)
{
float dp1 = DistToPt(p1, plane);
float[] dir = new float[3];
dir[0] = p2[0] - p1[0];
dir[1] = p2[1] - p1[1];
dir[2] = p2[2] - p1[2];
float dot1 = dir[0] * plane[0] + dir[1] * plane[1] + dir[2] * plane[2];
float dot2 = dp1 - plane[3];
float t = -(plane[3] + dot2) / dot1;
split.x = (dir[0] * t) + p1[0];
split.y = (dir[1] * t) + p1[1];
split.z = (dir[2] * t) + p1[2];
}
public static PlaneTriResult planeTriIntersection(float4 plane, FaceTri triangle, float epsilon, ref float3[] front, out int fcount, ref float3[] back, out int bcount)
{
fcount = 0;
bcount = 0;
// get the three vertices of the triangle.
float3 p1 = triangle.P1;
float3 p2 = triangle.P2;
float3 p3 = triangle.P3;
PlaneTriResult r1 = getSidePlane(p1, plane, epsilon); // compute the side of the plane each vertex is on
PlaneTriResult r2 = getSidePlane(p2, plane, epsilon);
PlaneTriResult r3 = getSidePlane(p3, plane, epsilon);
if (r1 == r2 && r1 == r3) // if all three vertices are on the same side of the plane.
{
if (r1 == PlaneTriResult.PTR_FRONT) // if all three are in front of the plane, then copy to the 'front' output triangle.
{
add(p1, front, ref fcount);
add(p2, front, ref fcount);
add(p3, front, ref fcount);
}
else
{
add(p1, back, ref bcount); // if all three are in 'back' then copy to the 'back' output triangle.
add(p2, back, ref bcount);
add(p3, back, ref bcount);
}
return r1; // if all three points are on the same side of the plane return result
}
// ok.. we need to split the triangle at the plane.
// First test ray segment P1 to P2
if (r1 == r2) // if these are both on the same side...
{
if (r1 == PlaneTriResult.PTR_FRONT)
{
add(p1, front, ref fcount);
add(p2, front, ref fcount);
}
else
{
add(p1, back, ref bcount);
add(p2, back, ref bcount);
}
}
else
{
float3 split = new float3();
intersect(p1, p2, split, plane);
if (r1 == PlaneTriResult.PTR_FRONT)
{
add(p1, front, ref fcount);
add(split, front, ref fcount);
add(split, back, ref bcount);
add(p2, back, ref bcount);
}
else
{
add(p1, back, ref bcount);
add(split, back, ref bcount);
add(split, front, ref fcount);
add(p2, front, ref fcount);
}
}
// Next test ray segment P2 to P3
if (r2 == r3) // if these are both on the same side...
{
if (r3 == PlaneTriResult.PTR_FRONT)
{
add(p3, front, ref fcount);
}
else
{
add(p3, back, ref bcount);
}
}
else
{
float3 split = new float3(); // split the point
intersect(p2, p3, split, plane);
if (r3 == PlaneTriResult.PTR_FRONT)
{
add(split, front, ref fcount);
add(split, back, ref bcount);
add(p3, front, ref fcount);
}
else
{
add(split, front, ref fcount);
add(split, back, ref bcount);
add(p3, back, ref bcount);
}
}
// Next test ray segment P3 to P1
if (r3 != r1) // if these are both on the same side...
{
float3 split = new float3(); // split the point
intersect(p3, p1, split, plane);
if (r1 == PlaneTriResult.PTR_FRONT)
{
add(split, front, ref fcount);
add(split, back, ref bcount);
}
else
{
add(split, front, ref fcount);
add(split, back, ref bcount);
}
}
return PlaneTriResult.PTR_SPLIT;
}
}
}

View File

@ -0,0 +1,36 @@
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
// General Information about an assembly is controlled through the following
// set of attributes. Change these attribute values to modify the information
// associated with an assembly.
[assembly: AssemblyTitle("ConvexDecompositionDotNet")]
[assembly: AssemblyDescription("")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("Intel Corporation")]
[assembly: AssemblyProduct("ConvexDecompositionDotNet")]
[assembly: AssemblyCopyright("Copyright © Intel Corporation 2010")]
[assembly: AssemblyTrademark("")]
[assembly: AssemblyCulture("")]
// Setting ComVisible to false makes the types in this assembly not visible
// to COM components. If you need to access a type in this assembly from
// COM, set the ComVisible attribute to true on that type.
[assembly: ComVisible(false)]
// The following GUID is for the ID of the typelib if this project is exposed to COM
[assembly: Guid("2a1c9467-1a17-4c8d-bf9f-4b4d86dd0cbb")]
// Version information for an assembly consists of the following four values:
//
// Major Version
// Minor Version
// Build Number
// Revision
//
// You can specify all the values or you can default the Build and Revision Numbers
// by using the '*' as shown below:
// [assembly: AssemblyVersion("1.0.*")]
[assembly: AssemblyVersion("1.0.0.0")]
[assembly: AssemblyFileVersion("1.0.0.0")]

View File

@ -0,0 +1,209 @@
/* The MIT License
*
* Copyright (c) 2010 Intel Corporation.
* All rights reserved.
*
* Based on the convexdecomposition library from
* <http://codesuppository.googlecode.com> by John W. Ratcliff and Stan Melax.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
using System;
namespace OpenSim.Region.Physics.ConvexDecompositionDotNet
{
public class Quaternion : float4
{
public Quaternion()
{
x = y = z = 0.0f;
w = 1.0f;
}
public Quaternion(float3 v, float t)
{
v = float3.normalize(v);
w = (float)Math.Cos(t / 2.0f);
v = v * (float)Math.Sin(t / 2.0f);
x = v.x;
y = v.y;
z = v.z;
}
public Quaternion(float _x, float _y, float _z, float _w)
{
x = _x;
y = _y;
z = _z;
w = _w;
}
public float angle()
{
return (float)Math.Acos(w) * 2.0f;
}
public float3 axis()
{
float3 a = new float3(x, y, z);
if (Math.Abs(angle()) < 0.0000001f)
return new float3(1f, 0f, 0f);
return a * (1 / (float)Math.Sin(angle() / 2.0f));
}
public float3 xdir()
{
return new float3(1 - 2 * (y * y + z * z), 2 * (x * y + w * z), 2 * (x * z - w * y));
}
public float3 ydir()
{
return new float3(2 * (x * y - w * z), 1 - 2 * (x * x + z * z), 2 * (y * z + w * x));
}
public float3 zdir()
{
return new float3(2 * (x * z + w * y), 2 * (y * z - w * x), 1 - 2 * (x * x + y * y));
}
public float3x3 getmatrix()
{
return new float3x3(xdir(), ydir(), zdir());
}
public static implicit operator float3x3(Quaternion q)
{
return q.getmatrix();
}
public static Quaternion operator *(Quaternion a, Quaternion b)
{
Quaternion c = new Quaternion();
c.w = a.w * b.w - a.x * b.x - a.y * b.y - a.z * b.z;
c.x = a.w * b.x + a.x * b.w + a.y * b.z - a.z * b.y;
c.y = a.w * b.y - a.x * b.z + a.y * b.w + a.z * b.x;
c.z = a.w * b.z + a.x * b.y - a.y * b.x + a.z * b.w;
return c;
}
public static float3 operator *(Quaternion q, float3 v)
{
// The following is equivalent to:
//return (q.getmatrix() * v);
float qx2 = q.x * q.x;
float qy2 = q.y * q.y;
float qz2 = q.z * q.z;
float qxqy = q.x * q.y;
float qxqz = q.x * q.z;
float qxqw = q.x * q.w;
float qyqz = q.y * q.z;
float qyqw = q.y * q.w;
float qzqw = q.z * q.w;
return new float3((1 - 2 * (qy2 + qz2)) * v.x + (2 * (qxqy - qzqw)) * v.y + (2 * (qxqz + qyqw)) * v.z, (2 * (qxqy + qzqw)) * v.x + (1 - 2 * (qx2 + qz2)) * v.y + (2 * (qyqz - qxqw)) * v.z, (2 * (qxqz - qyqw)) * v.x + (2 * (qyqz + qxqw)) * v.y + (1 - 2 * (qx2 + qy2)) * v.z);
}
public static Quaternion operator +(Quaternion a, Quaternion b)
{
return new Quaternion(a.x + b.x, a.y + b.y, a.z + b.z, a.w + b.w);
}
public static Quaternion operator *(Quaternion a, float b)
{
return new Quaternion(a.x *b, a.y *b, a.z *b, a.w *b);
}
public static Quaternion normalize(Quaternion a)
{
float m = (float)Math.Sqrt(a.w * a.w + a.x * a.x + a.y * a.y + a.z * a.z);
if (m < 0.000000001f)
{
a.w = 1;
a.x = a.y = a.z = 0;
return a;
}
return a * (1f / m);
}
public static float dot(Quaternion a, Quaternion b)
{
return (a.w * b.w + a.x * b.x + a.y * b.y + a.z * b.z);
}
public static Quaternion slerp(Quaternion a, Quaternion b, float interp)
{
if (dot(a, b) < 0.0)
{
a.w = -a.w;
a.x = -a.x;
a.y = -a.y;
a.z = -a.z;
}
float d = dot(a, b);
if (d >= 1.0)
{
return a;
}
float theta = (float)Math.Acos(d);
if (theta == 0.0f)
{
return (a);
}
return a * ((float)Math.Sin(theta - interp * theta) / (float)Math.Sin(theta)) + b * ((float)Math.Sin(interp * theta) / (float)Math.Sin(theta));
}
public static Quaternion Interpolate(Quaternion q0, Quaternion q1, float alpha)
{
return slerp(q0, q1, alpha);
}
public static Quaternion Inverse(Quaternion q)
{
return new Quaternion(-q.x, -q.y, -q.z, q.w);
}
public static Quaternion YawPitchRoll(float yaw, float pitch, float roll)
{
roll *= (3.14159264f / 180.0f);
yaw *= (3.14159264f / 180.0f);
pitch *= (3.14159264f / 180.0f);
return new Quaternion(new float3(0.0f, 0.0f, 1.0f), yaw) * new Quaternion(new float3(1.0f, 0.0f, 0.0f), pitch) * new Quaternion(new float3(0.0f, 1.0f, 0.0f), roll);
}
public static float Yaw(Quaternion q)
{
float3 v = q.ydir();
return (v.y == 0.0 && v.x == 0.0) ? 0.0f : (float)Math.Atan2(-v.x, v.y) * (180.0f / 3.14159264f);
}
public static float Pitch(Quaternion q)
{
float3 v = q.ydir();
return (float)Math.Atan2(v.z, Math.Sqrt(v.x * v.x + v.y * v.y)) * (180.0f / 3.14159264f);
}
public static float Roll(Quaternion q)
{
q = new Quaternion(new float3(0.0f, 0.0f, 1.0f), -Yaw(q) * (3.14159264f / 180.0f)) * q;
q = new Quaternion(new float3(1.0f, 0.0f, 0.0f), -Pitch(q) * (3.14159264f / 180.0f)) * q;
return (float)Math.Atan2(-q.xdir().z, q.xdir().x) * (180.0f / 3.14159264f);
}
}
}

View File

@ -0,0 +1,7 @@
ConvexDecompositionDotNet
=========================
A C# port of the ConvexDecomposition library by John W. Ratcliff and Stan Melax.
The original C++ version is available at <http://codesuppository.googlecode.com/>.
See the blog post at <http://codesuppository.blogspot.com/2006/08/approximate-convexdecomposition.html>
for a thorough explanation of generating convex hulls from concave meshes.

View File

@ -0,0 +1,265 @@
/* The MIT License
*
* Copyright (c) 2010 Intel Corporation.
* All rights reserved.
*
* Based on the convexdecomposition library from
* <http://codesuppository.googlecode.com> by John W. Ratcliff and Stan Melax.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
using System;
using System.Collections.Generic;
namespace OpenSim.Region.Physics.ConvexDecompositionDotNet
{
public class Rect3d
{
public float[] mMin = new float[3];
public float[] mMax = new float[3];
public Rect3d()
{
}
public Rect3d(float[] bmin, float[] bmax)
{
mMin[0] = bmin[0];
mMin[1] = bmin[1];
mMin[2] = bmin[2];
mMax[0] = bmax[0];
mMax[1] = bmax[1];
mMax[2] = bmax[2];
}
public void SetMin(float[] bmin)
{
mMin[0] = bmin[0];
mMin[1] = bmin[1];
mMin[2] = bmin[2];
}
public void SetMax(float[] bmax)
{
mMax[0] = bmax[0];
mMax[1] = bmax[1];
mMax[2] = bmax[2];
}
public void SetMin(float x, float y, float z)
{
mMin[0] = x;
mMin[1] = y;
mMin[2] = z;
}
public void SetMax(float x, float y, float z)
{
mMax[0] = x;
mMax[1] = y;
mMax[2] = z;
}
}
public static class SplitPlane
{
public static bool computeSplitPlane(List<float3> vertices, List<int> indices, ref float4 plane)
{
float[] bmin = { Single.MaxValue, Single.MaxValue, Single.MaxValue };
float[] bmax = { Single.MinValue, Single.MinValue, Single.MinValue };
for (int i = 0; i < vertices.Count; i++)
{
float3 p = vertices[i];
if (p[0] < bmin[0])
bmin[0] = p[0];
if (p[1] < bmin[1])
bmin[1] = p[1];
if (p[2] < bmin[2])
bmin[2] = p[2];
if (p[0] > bmax[0])
bmax[0] = p[0];
if (p[1] > bmax[1])
bmax[1] = p[1];
if (p[2] > bmax[2])
bmax[2] = p[2];
}
float dx = bmax[0] - bmin[0];
float dy = bmax[1] - bmin[1];
float dz = bmax[2] - bmin[2];
float laxis = dx;
int axis = 0;
if (dy > dx)
{
axis = 1;
laxis = dy;
}
if (dz > dx && dz > dy)
{
axis = 2;
laxis = dz;
}
float[] p1 = new float[3];
float[] p2 = new float[3];
float[] p3 = new float[3];
p3[0] = p2[0] = p1[0] = bmin[0] + dx * 0.5f;
p3[1] = p2[1] = p1[1] = bmin[1] + dy * 0.5f;
p3[2] = p2[2] = p1[2] = bmin[2] + dz * 0.5f;
Rect3d b = new Rect3d(bmin, bmax);
Rect3d b1 = new Rect3d();
Rect3d b2 = new Rect3d();
splitRect(axis, b, b1, b2, p1);
switch (axis)
{
case 0:
p2[1] = bmin[1];
p2[2] = bmin[2];
if (dz > dy)
{
p3[1] = bmax[1];
p3[2] = bmin[2];
}
else
{
p3[1] = bmin[1];
p3[2] = bmax[2];
}
break;
case 1:
p2[0] = bmin[0];
p2[2] = bmin[2];
if (dx > dz)
{
p3[0] = bmax[0];
p3[2] = bmin[2];
}
else
{
p3[0] = bmin[0];
p3[2] = bmax[2];
}
break;
case 2:
p2[0] = bmin[0];
p2[1] = bmin[1];
if (dx > dy)
{
p3[0] = bmax[0];
p3[1] = bmin[1];
}
else
{
p3[0] = bmin[0];
p3[1] = bmax[1];
}
break;
}
computePlane(p1, p2, p3, plane);
return true;
}
internal static void computePlane(float[] A, float[] B, float[] C, float4 plane)
{
float vx = (B[0] - C[0]);
float vy = (B[1] - C[1]);
float vz = (B[2] - C[2]);
float wx = (A[0] - B[0]);
float wy = (A[1] - B[1]);
float wz = (A[2] - B[2]);
float vw_x = vy * wz - vz * wy;
float vw_y = vz * wx - vx * wz;
float vw_z = vx * wy - vy * wx;
float mag = (float)Math.Sqrt((vw_x * vw_x) + (vw_y * vw_y) + (vw_z * vw_z));
if (mag < 0.000001f)
{
mag = 0;
}
else
{
mag = 1.0f / mag;
}
float x = vw_x * mag;
float y = vw_y * mag;
float z = vw_z * mag;
float D = 0.0f - ((x * A[0]) + (y * A[1]) + (z * A[2]));
plane.x = x;
plane.y = y;
plane.z = z;
plane.w = D;
}
public static void splitRect(int axis, Rect3d source, Rect3d b1, Rect3d b2, float[] midpoint)
{
switch (axis)
{
case 0:
b1.SetMin(source.mMin);
b1.SetMax(midpoint[0], source.mMax[1], source.mMax[2]);
b2.SetMin(midpoint[0], source.mMin[1], source.mMin[2]);
b2.SetMax(source.mMax);
break;
case 1:
b1.SetMin(source.mMin);
b1.SetMax(source.mMax[0], midpoint[1], source.mMax[2]);
b2.SetMin(source.mMin[0], midpoint[1], source.mMin[2]);
b2.SetMax(source.mMax);
break;
case 2:
b1.SetMin(source.mMin);
b1.SetMax(source.mMax[0], source.mMax[1], midpoint[2]);
b2.SetMin(source.mMin[0], source.mMin[1], midpoint[2]);
b2.SetMax(source.mMax);
break;
}
}
}
}

View File

@ -0,0 +1,70 @@
/* The MIT License
*
* Copyright (c) 2010 Intel Corporation.
* All rights reserved.
*
* Based on the convexdecomposition library from
* <http://codesuppository.googlecode.com> by John W. Ratcliff and Stan Melax.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
using System;
using System.Collections.Generic;
namespace OpenSim.Region.Physics.ConvexDecompositionDotNet
{
public class VertexPool
{
private List<float3> mVertices = new List<float3>();
private Dictionary<float3, int> mIndices = new Dictionary<float3, int>();
public int getIndex(float3 vtx)
{
int idx;
if (mIndices.TryGetValue(vtx, out idx))
return idx;
idx = mVertices.Count;
mVertices.Add(vtx);
mIndices.Add(vtx, idx);
return idx;
}
public float3 Get(int idx)
{
return mVertices[idx];
}
public int GetSize()
{
return mVertices.Count;
}
public List<float3> GetVertices()
{
return mVertices;
}
public void Clear()
{
mVertices.Clear();
}
}
}

View File

@ -0,0 +1,70 @@
/* The MIT License
*
* Copyright (c) 2010 Intel Corporation.
* All rights reserved.
*
* Based on the convexdecomposition library from
* <http://codesuppository.googlecode.com> by John W. Ratcliff and Stan Melax.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
using System;
namespace OpenSim.Region.Physics.ConvexDecompositionDotNet
{
public class float2
{
public float x;
public float y;
public float2()
{
}
public float2(float _x, float _y)
{
x = _x;
y = _y;
}
public float this[int i]
{
get
{
switch (i)
{
case 0: return x;
case 1: return y;
}
throw new ArgumentOutOfRangeException();
}
}
public static float2 operator -(float2 a, float2 b)
{
return new float2(a.x - b.x, a.y - b.y);
}
public static float2 operator +(float2 a, float2 b)
{
return new float2(a.x + b.x, a.y + b.y);
}
}
}

View File

@ -0,0 +1,444 @@
/* The MIT License
*
* Copyright (c) 2010 Intel Corporation.
* All rights reserved.
*
* Based on the convexdecomposition library from
* <http://codesuppository.googlecode.com> by John W. Ratcliff and Stan Melax.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
using System;
namespace OpenSim.Region.Physics.ConvexDecompositionDotNet
{
public class float3 : IEquatable<float3>
{
public float x;
public float y;
public float z;
public float3()
{
x = 0;
y = 0;
z = 0;
}
public float3(float _x, float _y, float _z)
{
x = _x;
y = _y;
z = _z;
}
public float3(float3 f)
{
x = f.x;
y = f.y;
z = f.z;
}
public float this[int i]
{
get
{
switch (i)
{
case 0: return x;
case 1: return y;
case 2: return z;
}
throw new ArgumentOutOfRangeException();
}
}
public float Distance(float3 a)
{
float3 d = new float3(a.x - x, a.y - y, a.z - z);
return d.Length();
}
public float Distance2(float3 a)
{
float dx = a.x - x;
float dy = a.y - y;
float dz = a.z - z;
return dx * dx + dy * dy + dz * dz;
}
public float Length()
{
return (float)Math.Sqrt(x * x + y * y + z * z);
}
public float Area(float3 p1, float3 p2)
{
float A = Partial(p1);
A += p1.Partial(p2);
A += p2.Partial(this);
return A * 0.5f;
}
public float Partial(float3 p)
{
return (x * p.y) - (p.x * y);
}
// Given a point and a line (defined by two points), compute the closest point
// in the line. (The line is treated as infinitely long.)
public void NearestPointInLine(float3 point, float3 line0, float3 line1)
{
float3 nearestPoint = new float3();
float3 lineDelta = line1 - line0;
// Handle degenerate lines
if (lineDelta == float3.Zero)
{
nearestPoint = line0;
}
else
{
float delta = float3.dot(point - line0, lineDelta) / float3.dot(lineDelta, lineDelta);
nearestPoint = line0 + lineDelta * delta;
}
this.x = nearestPoint.x;
this.y = nearestPoint.y;
this.z = nearestPoint.z;
}
// Given a point and a line segment (defined by two points), compute the closest point
// in the line. Cap the point at the endpoints of the line segment.
public void NearestPointInLineSegment(float3 point, float3 line0, float3 line1)
{
float3 nearestPoint = new float3();
float3 lineDelta = line1 - line0;
// Handle degenerate lines
if (lineDelta == Zero)
{
nearestPoint = line0;
}
else
{
float delta = float3.dot(point - line0, lineDelta) / float3.dot(lineDelta, lineDelta);
// Clamp the point to conform to the segment's endpoints
if (delta < 0)
delta = 0;
else if (delta > 1)
delta = 1;
nearestPoint = line0 + lineDelta * delta;
}
this.x = nearestPoint.x;
this.y = nearestPoint.y;
this.z = nearestPoint.z;
}
// Given a point and a triangle (defined by three points), compute the closest point
// in the triangle. Clamp the point so it's confined to the area of the triangle.
public void NearestPointInTriangle(float3 point, float3 triangle0, float3 triangle1, float3 triangle2)
{
float3 nearestPoint = new float3();
float3 lineDelta0 = triangle1 - triangle0;
float3 lineDelta1 = triangle2 - triangle0;
// Handle degenerate triangles
if ((lineDelta0 == Zero) || (lineDelta1 == Zero))
{
nearestPoint.NearestPointInLineSegment(point, triangle1, triangle2);
}
else if (lineDelta0 == lineDelta1)
{
nearestPoint.NearestPointInLineSegment(point, triangle0, triangle1);
}
else
{
float3[] axis = new float3[3] { new float3(), new float3(), new float3() };
axis[0].NearestPointInLine(triangle0, triangle1, triangle2);
axis[1].NearestPointInLine(triangle1, triangle0, triangle2);
axis[2].NearestPointInLine(triangle2, triangle0, triangle1);
float3 axisDot = new float3();
axisDot.x = dot(triangle0 - axis[0], point - axis[0]);
axisDot.y = dot(triangle1 - axis[1], point - axis[1]);
axisDot.z = dot(triangle2 - axis[2], point - axis[2]);
bool bForce = true;
float bestMagnitude2 = 0;
float closeMagnitude2;
float3 closePoint = new float3();
if (axisDot.x < 0f)
{
closePoint.NearestPointInLineSegment(point, triangle1, triangle2);
closeMagnitude2 = point.Distance2(closePoint);
if (bForce || (bestMagnitude2 > closeMagnitude2))
{
bForce = false;
bestMagnitude2 = closeMagnitude2;
nearestPoint = closePoint;
}
}
if (axisDot.y < 0f)
{
closePoint.NearestPointInLineSegment(point, triangle0, triangle2);
closeMagnitude2 = point.Distance2(closePoint);
if (bForce || (bestMagnitude2 > closeMagnitude2))
{
bForce = false;
bestMagnitude2 = closeMagnitude2;
nearestPoint = closePoint;
}
}
if (axisDot.z < 0f)
{
closePoint.NearestPointInLineSegment(point, triangle0, triangle1);
closeMagnitude2 = point.Distance2(closePoint);
if (bForce || (bestMagnitude2 > closeMagnitude2))
{
bForce = false;
bestMagnitude2 = closeMagnitude2;
nearestPoint = closePoint;
}
}
// If bForce is true at this point, it means the nearest point lies
// inside the triangle; use the nearest-point-on-a-plane equation
if (bForce)
{
float3 normal;
// Get the normal of the polygon (doesn't have to be a unit vector)
normal = float3.cross(lineDelta0, lineDelta1);
float3 pointDelta = point - triangle0;
float delta = float3.dot(normal, pointDelta) / float3.dot(normal, normal);
nearestPoint = point - normal * delta;
}
}
this.x = nearestPoint.x;
this.y = nearestPoint.y;
this.z = nearestPoint.z;
}
public static float3 operator +(float3 a, float3 b)
{
return new float3(a.x + b.x, a.y + b.y, a.z + b.z);
}
public static float3 operator -(float3 a, float3 b)
{
return new float3(a.x - b.x, a.y - b.y, a.z - b.z);
}
public static float3 operator -(float3 a, float s)
{
return new float3(a.x - s, a.y - s, a.z - s);
}
public static float3 operator -(float3 v)
{
return new float3(-v.x, -v.y, -v.z);
}
public static float3 operator *(float3 v, float s)
{
return new float3(v.x * s, v.y * s, v.z * s);
}
public static float3 operator *(float s, float3 v)
{
return new float3(v.x * s, v.y * s, v.z * s);
}
public static float3 operator *(float3 v, float3x3 m)
{
return new float3((m.x.x * v.x + m.y.x * v.y + m.z.x * v.z), (m.x.y * v.x + m.y.y * v.y + m.z.y * v.z), (m.x.z * v.x + m.y.z * v.y + m.z.z * v.z));
}
public static float3 operator *(float3x3 m, float3 v)
{
return new float3(dot(m.x, v), dot(m.y, v), dot(m.z, v));
}
public static float3 operator /(float3 v, float s)
{
float sinv = 1.0f / s;
return new float3(v.x * sinv, v.y * sinv, v.z * sinv);
}
public bool Equals(float3 other)
{
return this == other;
}
public override bool Equals(object obj)
{
float3 f = obj as float3;
if (f == null)
return false;
return this == f;
}
public override int GetHashCode()
{
return x.GetHashCode() ^ y.GetHashCode() ^ z.GetHashCode();
}
public static bool operator ==(float3 a, float3 b)
{
// If both are null, or both are same instance, return true.
if (System.Object.ReferenceEquals(a, b))
return true;
// If one is null, but not both, return false.
if (((object)a == null) || ((object)b == null))
return false;
return (a.x == b.x && a.y == b.y && a.z == b.z);
}
public static bool operator !=(float3 a, float3 b)
{
return (a.x != b.x || a.y != b.y || a.z != b.z);
}
public static float dot(float3 a, float3 b)
{
return a.x * b.x + a.y * b.y + a.z * b.z;
}
public static float3 cmul(float3 v1, float3 v2)
{
return new float3(v1.x * v2.x, v1.y * v2.y, v1.z * v2.z);
}
public static float3 cross(float3 a, float3 b)
{
return new float3(a.y * b.z - a.z * b.y, a.z * b.x - a.x * b.z, a.x * b.y - a.y * b.x);
}
public static float3 Interpolate(float3 v0, float3 v1, float alpha)
{
return v0 * (1 - alpha) + v1 * alpha;
}
public static float3 Round(float3 a, int digits)
{
return new float3((float)Math.Round(a.x, digits), (float)Math.Round(a.y, digits), (float)Math.Round(a.z, digits));
}
public static float3 VectorMax(float3 a, float3 b)
{
return new float3(Math.Max(a.x, b.x), Math.Max(a.y, b.y), Math.Max(a.z, b.z));
}
public static float3 VectorMin(float3 a, float3 b)
{
return new float3(Math.Min(a.x, b.x), Math.Min(a.y, b.y), Math.Min(a.z, b.z));
}
public static float3 vabs(float3 v)
{
return new float3(Math.Abs(v.x), Math.Abs(v.y), Math.Abs(v.z));
}
public static float magnitude(float3 v)
{
return (float)Math.Sqrt(v.x * v.x + v.y * v.y + v.z * v.z);
}
public static float3 normalize(float3 v)
{
float d = magnitude(v);
if (d == 0)
d = 0.1f;
d = 1 / d;
return new float3(v.x * d, v.y * d, v.z * d);
}
public static float3 safenormalize(float3 v)
{
if (magnitude(v) <= 0.0f)
return new float3(1, 0, 0);
else
return normalize(v);
}
public static float Yaw(float3 v)
{
return (v.y == 0.0 && v.x == 0.0) ? 0.0f : (float)Math.Atan2(-v.x, v.y) * (180.0f / 3.14159264f);
}
public static float Pitch(float3 v)
{
return (float)Math.Atan2(v.z, Math.Sqrt(v.x * v.x + v.y * v.y)) * (180.0f / 3.14159264f);
}
public float ComputePlane(float3 A, float3 B, float3 C)
{
float vx, vy, vz, wx, wy, wz, vw_x, vw_y, vw_z, mag;
vx = (B.x - C.x);
vy = (B.y - C.y);
vz = (B.z - C.z);
wx = (A.x - B.x);
wy = (A.y - B.y);
wz = (A.z - B.z);
vw_x = vy * wz - vz * wy;
vw_y = vz * wx - vx * wz;
vw_z = vx * wy - vy * wx;
mag = (float)Math.Sqrt((vw_x * vw_x) + (vw_y * vw_y) + (vw_z * vw_z));
if (mag < 0.000001f)
{
mag = 0;
}
else
{
mag = 1.0f / mag;
}
x = vw_x * mag;
y = vw_y * mag;
z = vw_z * mag;
float D = 0.0f - ((x * A.x) + (y * A.y) + (z * A.z));
return D;
}
public override string ToString()
{
return String.Format("<{0}, {1}, {2}>", x, y, z);
}
public static readonly float3 Zero = new float3();
}
}

View File

@ -0,0 +1,195 @@
/* The MIT License
*
* Copyright (c) 2010 Intel Corporation.
* All rights reserved.
*
* Based on the convexdecomposition library from
* <http://codesuppository.googlecode.com> by John W. Ratcliff and Stan Melax.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
using System;
using System.Collections.Generic;
using System.Diagnostics;
namespace OpenSim.Region.Physics.ConvexDecompositionDotNet
{
public class float3x3
{
public float3 x = new float3();
public float3 y = new float3();
public float3 z = new float3();
public float3x3()
{
}
public float3x3(float xx, float xy, float xz, float yx, float yy, float yz, float zx, float zy, float zz)
{
x = new float3(xx, xy, xz);
y = new float3(yx, yy, yz);
z = new float3(zx, zy, zz);
}
public float3x3(float3 _x, float3 _y, float3 _z)
{
x = new float3(_x);
y = new float3(_y);
z = new float3(_z);
}
public float3 this[int i]
{
get
{
switch (i)
{
case 0: return x;
case 1: return y;
case 2: return z;
}
throw new ArgumentOutOfRangeException();
}
}
public float this[int i, int j]
{
get
{
switch (i)
{
case 0:
switch (j)
{
case 0: return x.x;
case 1: return x.y;
case 2: return x.z;
}
break;
case 1:
switch (j)
{
case 0: return y.x;
case 1: return y.y;
case 2: return y.z;
}
break;
case 2:
switch (j)
{
case 0: return z.x;
case 1: return z.y;
case 2: return z.z;
}
break;
}
throw new ArgumentOutOfRangeException();
}
set
{
switch (i)
{
case 0:
switch (j)
{
case 0: x.x = value; return;
case 1: x.y = value; return;
case 2: x.z = value; return;
}
break;
case 1:
switch (j)
{
case 0: y.x = value; return;
case 1: y.y = value; return;
case 2: y.z = value; return;
}
break;
case 2:
switch (j)
{
case 0: z.x = value; return;
case 1: z.y = value; return;
case 2: z.z = value; return;
}
break;
}
throw new ArgumentOutOfRangeException();
}
}
public static float3x3 Transpose(float3x3 m)
{
return new float3x3(new float3(m.x.x, m.y.x, m.z.x), new float3(m.x.y, m.y.y, m.z.y), new float3(m.x.z, m.y.z, m.z.z));
}
public static float3x3 operator *(float3x3 a, float3x3 b)
{
return new float3x3(a.x * b, a.y * b, a.z * b);
}
public static float3x3 operator *(float3x3 a, float s)
{
return new float3x3(a.x * s, a.y * s, a.z * s);
}
public static float3x3 operator /(float3x3 a, float s)
{
float t = 1f / s;
return new float3x3(a.x * t, a.y * t, a.z * t);
}
public static float3x3 operator +(float3x3 a, float3x3 b)
{
return new float3x3(a.x + b.x, a.y + b.y, a.z + b.z);
}
public static float3x3 operator -(float3x3 a, float3x3 b)
{
return new float3x3(a.x - b.x, a.y - b.y, a.z - b.z);
}
public static float Determinant(float3x3 m)
{
return m.x.x * m.y.y * m.z.z + m.y.x * m.z.y * m.x.z + m.z.x * m.x.y * m.y.z - m.x.x * m.z.y * m.y.z - m.y.x * m.x.y * m.z.z - m.z.x * m.y.y * m.x.z;
}
public static float3x3 Inverse(float3x3 a)
{
float3x3 b = new float3x3();
float d = Determinant(a);
Debug.Assert(d != 0);
for (int i = 0; i < 3; i++)
{
for (int j = 0; j < 3; j++)
{
int i1 = (i + 1) % 3;
int i2 = (i + 2) % 3;
int j1 = (j + 1) % 3;
int j2 = (j + 2) % 3;
// reverse indexs i&j to take transpose
b[i, j] = (a[i1][j1] * a[i2][j2] - a[i1][j2] * a[i2][j1]) / d;
}
}
return b;
}
}
}

View File

@ -0,0 +1,170 @@
/* The MIT License
*
* Copyright (c) 2010 Intel Corporation.
* All rights reserved.
*
* Based on the convexdecomposition library from
* <http://codesuppository.googlecode.com> by John W. Ratcliff and Stan Melax.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
using System;
namespace OpenSim.Region.Physics.ConvexDecompositionDotNet
{
public class float4
{
public float x;
public float y;
public float z;
public float w;
public float4()
{
x = 0;
y = 0;
z = 0;
w = 0;
}
public float4(float _x, float _y, float _z, float _w)
{
x = _x;
y = _y;
z = _z;
w = _w;
}
public float4(float3 v, float _w)
{
x = v.x;
y = v.y;
z = v.z;
w = _w;
}
public float4(float4 f)
{
x = f.x;
y = f.y;
z = f.z;
w = f.w;
}
public float this[int i]
{
get
{
switch (i)
{
case 0: return x;
case 1: return y;
case 2: return z;
case 3: return w;
}
throw new ArgumentOutOfRangeException();
}
}
public float3 xyz()
{
return new float3(x, y, z);
}
public void setxyz(float3 xyz)
{
x = xyz.x;
y = xyz.y;
z = xyz.z;
}
public override int GetHashCode()
{
return x.GetHashCode() ^ y.GetHashCode() ^ z.GetHashCode() ^ w.GetHashCode();
}
public override bool Equals(object obj)
{
float4 f = obj as float4;
if (f == null)
return false;
return this == f;
}
public static float4 Homogenize(float3 v3)
{
return Homogenize(v3, 1.0f);
}
//C++ TO C# CONVERTER NOTE: C# does not allow default values for parameters. Overloaded methods are inserted above.
//ORIGINAL LINE: float4 Homogenize(const float3 &v3, const float &w =1.0f)
public static float4 Homogenize(float3 v3, float w)
{
return new float4(v3.x, v3.y, v3.z, w);
}
public static float4 cmul(float4 a, float4 b)
{
return new float4(a.x * b.x, a.y * b.y, a.z * b.z, a.w * b.w);
}
public static float4 operator +(float4 a, float4 b)
{
return new float4(a.x + b.x, a.y + b.y, a.z + b.z, a.w + b.w);
}
public static float4 operator -(float4 a, float4 b)
{
return new float4(a.x - b.x, a.y - b.y, a.z - b.z, a.w - b.w);
}
public static float4 operator *(float4 v, float4x4 m)
{
return v.x * m.x + v.y * m.y + v.z * m.z + v.w * m.w; // yes this actually works
}
public static bool operator ==(float4 a, float4 b)
{
// If both are null, or both are same instance, return true.
if (System.Object.ReferenceEquals(a, b))
return true;
// If one is null, but not both, return false.
if (((object)a == null) || ((object)b == null))
return false;
return (a.x == b.x && a.y == b.y && a.z == b.z && a.w == b.w);
}
public static bool operator !=(float4 a, float4 b)
{
return !(a == b);
}
public static float4 operator *(float4 v, float s)
{
return new float4(v.x * s, v.y * s, v.z * s, v.w * s);
}
public static float4 operator *(float s, float4 v)
{
return new float4(v.x * s, v.y * s, v.z * s, v.w * s);
}
}
}

View File

@ -0,0 +1,284 @@
/* The MIT License
*
* Copyright (c) 2010 Intel Corporation.
* All rights reserved.
*
* Based on the convexdecomposition library from
* <http://codesuppository.googlecode.com> by John W. Ratcliff and Stan Melax.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace OpenSim.Region.Physics.ConvexDecompositionDotNet
{
public class float4x4
{
public float4 x = new float4();
public float4 y = new float4();
public float4 z = new float4();
public float4 w = new float4();
public float4x4()
{
}
public float4x4(float4 _x, float4 _y, float4 _z, float4 _w)
{
x = new float4(_x);
y = new float4(_y);
z = new float4(_z);
w = new float4(_w);
}
public float4x4(
float m00, float m01, float m02, float m03,
float m10, float m11, float m12, float m13,
float m20, float m21, float m22, float m23,
float m30, float m31, float m32, float m33)
{
x = new float4(m00, m01, m02, m03);
y = new float4(m10, m11, m12, m13);
z = new float4(m20, m21, m22, m23);
w = new float4(m30, m31, m32, m33);
}
public float4x4(float4x4 m)
{
x = new float4(m.x);
y = new float4(m.y);
z = new float4(m.z);
w = new float4(m.w);
}
public float4 this[int i]
{
get
{
switch (i)
{
case 0: return x;
case 1: return y;
case 2: return z;
case 3: return w;
}
throw new ArgumentOutOfRangeException();
}
set
{
switch (i)
{
case 0: x = value; return;
case 1: y = value; return;
case 2: z = value; return;
case 3: w = value; return;
}
throw new ArgumentOutOfRangeException();
}
}
public override int GetHashCode()
{
return x.GetHashCode() ^ y.GetHashCode() ^ z.GetHashCode() ^ w.GetHashCode();
}
public override bool Equals(object obj)
{
float4x4 m = obj as float4x4;
if (m == null)
return false;
return this == m;
}
public static float4x4 operator *(float4x4 a, float4x4 b)
{
return new float4x4(a.x * b, a.y * b, a.z * b, a.w * b);
}
public static bool operator ==(float4x4 a, float4x4 b)
{
return (a.x == b.x && a.y == b.y && a.z == b.z && a.w == b.w);
}
public static bool operator !=(float4x4 a, float4x4 b)
{
return !(a == b);
}
public static float4x4 Inverse(float4x4 m)
{
float4x4 d = new float4x4();
//float dst = d.x.x;
float[] tmp = new float[12]; // temp array for pairs
float[] src = new float[16]; // array of transpose source matrix
float det; // determinant
// transpose matrix
for (int i = 0; i < 4; i++)
{
src[i] = m[i].x;
src[i + 4] = m[i].y;
src[i + 8] = m[i].z;
src[i + 12] = m[i].w;
}
// calculate pairs for first 8 elements (cofactors)
tmp[0] = src[10] * src[15];
tmp[1] = src[11] * src[14];
tmp[2] = src[9] * src[15];
tmp[3] = src[11] * src[13];
tmp[4] = src[9] * src[14];
tmp[5] = src[10] * src[13];
tmp[6] = src[8] * src[15];
tmp[7] = src[11] * src[12];
tmp[8] = src[8] * src[14];
tmp[9] = src[10] * src[12];
tmp[10] = src[8] * src[13];
tmp[11] = src[9] * src[12];
// calculate first 8 elements (cofactors)
d.x.x = tmp[0]*src[5] + tmp[3]*src[6] + tmp[4]*src[7];
d.x.x -= tmp[1]*src[5] + tmp[2]*src[6] + tmp[5]*src[7];
d.x.y = tmp[1]*src[4] + tmp[6]*src[6] + tmp[9]*src[7];
d.x.y -= tmp[0]*src[4] + tmp[7]*src[6] + tmp[8]*src[7];
d.x.z = tmp[2]*src[4] + tmp[7]*src[5] + tmp[10]*src[7];
d.x.z -= tmp[3]*src[4] + tmp[6]*src[5] + tmp[11]*src[7];
d.x.w = tmp[5]*src[4] + tmp[8]*src[5] + tmp[11]*src[6];
d.x.w -= tmp[4]*src[4] + tmp[9]*src[5] + tmp[10]*src[6];
d.y.x = tmp[1]*src[1] + tmp[2]*src[2] + tmp[5]*src[3];
d.y.x -= tmp[0]*src[1] + tmp[3]*src[2] + tmp[4]*src[3];
d.y.y = tmp[0]*src[0] + tmp[7]*src[2] + tmp[8]*src[3];
d.y.y -= tmp[1]*src[0] + tmp[6]*src[2] + tmp[9]*src[3];
d.y.z = tmp[3]*src[0] + tmp[6]*src[1] + tmp[11]*src[3];
d.y.z -= tmp[2]*src[0] + tmp[7]*src[1] + tmp[10]*src[3];
d.y.w = tmp[4]*src[0] + tmp[9]*src[1] + tmp[10]*src[2];
d.y.w -= tmp[5]*src[0] + tmp[8]*src[1] + tmp[11]*src[2];
// calculate pairs for second 8 elements (cofactors)
tmp[0] = src[2]*src[7];
tmp[1] = src[3]*src[6];
tmp[2] = src[1]*src[7];
tmp[3] = src[3]*src[5];
tmp[4] = src[1]*src[6];
tmp[5] = src[2]*src[5];
tmp[6] = src[0]*src[7];
tmp[7] = src[3]*src[4];
tmp[8] = src[0]*src[6];
tmp[9] = src[2]*src[4];
tmp[10] = src[0]*src[5];
tmp[11] = src[1]*src[4];
// calculate second 8 elements (cofactors)
d.z.x = tmp[0]*src[13] + tmp[3]*src[14] + tmp[4]*src[15];
d.z.x -= tmp[1]*src[13] + tmp[2]*src[14] + tmp[5]*src[15];
d.z.y = tmp[1]*src[12] + tmp[6]*src[14] + tmp[9]*src[15];
d.z.y -= tmp[0]*src[12] + tmp[7]*src[14] + tmp[8]*src[15];
d.z.z = tmp[2]*src[12] + tmp[7]*src[13] + tmp[10]*src[15];
d.z.z -= tmp[3]*src[12] + tmp[6]*src[13] + tmp[11]*src[15];
d.z.w = tmp[5]*src[12] + tmp[8]*src[13] + tmp[11]*src[14];
d.z.w-= tmp[4]*src[12] + tmp[9]*src[13] + tmp[10]*src[14];
d.w.x = tmp[2]*src[10] + tmp[5]*src[11] + tmp[1]*src[9];
d.w.x-= tmp[4]*src[11] + tmp[0]*src[9] + tmp[3]*src[10];
d.w.y = tmp[8]*src[11] + tmp[0]*src[8] + tmp[7]*src[10];
d.w.y-= tmp[6]*src[10] + tmp[9]*src[11] + tmp[1]*src[8];
d.w.z = tmp[6]*src[9] + tmp[11]*src[11] + tmp[3]*src[8];
d.w.z-= tmp[10]*src[11] + tmp[2]*src[8] + tmp[7]*src[9];
d.w.w = tmp[10]*src[10] + tmp[4]*src[8] + tmp[9]*src[9];
d.w.w-= tmp[8]*src[9] + tmp[11]*src[10] + tmp[5]*src[8];
// calculate determinant
det = src[0] * d.x.x + src[1] * d.x.y + src[2] * d.x.z + src[3] * d.x.w;
// calculate matrix inverse
det = 1/det;
for (int j = 0; j < 4; j++)
d[j] *= det;
return d;
}
public static float4x4 MatrixRigidInverse(float4x4 m)
{
float4x4 trans_inverse = MatrixTranslation(-m.w.xyz());
float4x4 rot = new float4x4(m);
rot.w = new float4(0f, 0f, 0f, 1f);
return trans_inverse * MatrixTranspose(rot);
}
public static float4x4 MatrixTranspose(float4x4 m)
{
return new float4x4(m.x.x, m.y.x, m.z.x, m.w.x, m.x.y, m.y.y, m.z.y, m.w.y, m.x.z, m.y.z, m.z.z, m.w.z, m.x.w, m.y.w, m.z.w, m.w.w);
}
public static float4x4 MatrixPerspectiveFov(float fovy, float aspect, float zn, float zf)
{
float h = 1.0f / (float)Math.Tan(fovy / 2.0f); // view space height
float w = h / aspect; // view space width
return new float4x4(w, 0, 0, 0, 0, h, 0, 0, 0, 0, zf / (zn - zf), -1, 0, 0, zn * zf / (zn - zf), 0);
}
public static float4x4 MatrixTranslation(float3 t)
{
return new float4x4(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, t.x, t.y, t.z, 1);
}
public static float4x4 MatrixRotationZ(float angle_radians)
{
float s = (float)Math.Sin(angle_radians);
float c = (float)Math.Cos(angle_radians);
return new float4x4(c, s, 0, 0, -s, c, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1);
}
public static float4x4 MatrixLookAt(float3 eye, float3 at, float3 up)
{
float4x4 m = new float4x4();
m.w.w = 1.0f;
m.w.setxyz(eye);
m.z.setxyz(float3.normalize(eye - at));
m.x.setxyz(float3.normalize(float3.cross(up, m.z.xyz())));
m.y.setxyz(float3.cross(m.z.xyz(), m.x.xyz()));
return MatrixRigidInverse(m);
}
public static float4x4 MatrixFromQuatVec(Quaternion q, float3 v)
{
// builds a 4x4 transformation matrix based on orientation q and translation v
float qx2 = q.x * q.x;
float qy2 = q.y * q.y;
float qz2 = q.z * q.z;
float qxqy = q.x * q.y;
float qxqz = q.x * q.z;
float qxqw = q.x * q.w;
float qyqz = q.y * q.z;
float qyqw = q.y * q.w;
float qzqw = q.z * q.w;
return new float4x4(
1 - 2 * (qy2 + qz2),
2 * (qxqy + qzqw),
2 * (qxqz - qyqw),
0,
2 * (qxqy - qzqw),
1 - 2 * (qx2 + qz2),
2 * (qyqz + qxqw),
0,
2 * (qxqz + qyqw),
2 * (qyqz - qxqw),
1 - 2 * (qx2 + qy2),
0,
v.x,
v.y,
v.z,
1.0f);
}
}
}

View File

@ -0,0 +1,128 @@
/* The MIT License
*
* Copyright (c) 2010 Intel Corporation.
* All rights reserved.
*
* Based on the convexdecomposition library from
* <http://codesuppository.googlecode.com> by John W. Ratcliff and Stan Melax.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
using System;
namespace OpenSim.Region.Physics.ConvexDecompositionDotNet
{
public class int3
{
public int x;
public int y;
public int z;
public int3()
{
}
public int3(int _x, int _y, int _z)
{
x = _x;
y = _y;
z = _z;
}
public int this[int i]
{
get
{
switch (i)
{
case 0: return x;
case 1: return y;
case 2: return z;
}
throw new ArgumentOutOfRangeException();
}
set
{
switch (i)
{
case 0: x = value; return;
case 1: y = value; return;
case 2: z = value; return;
}
throw new ArgumentOutOfRangeException();
}
}
public override int GetHashCode()
{
return x.GetHashCode() ^ y.GetHashCode() ^ z.GetHashCode();
}
public override bool Equals(object obj)
{
int3 i = obj as int3;
if (i == null)
return false;
return this == i;
}
public static bool operator ==(int3 a, int3 b)
{
// If both are null, or both are same instance, return true.
if (System.Object.ReferenceEquals(a, b))
return true;
// If one is null, but not both, return false.
if (((object)a == null) || ((object)b == null))
return false;
for (int i = 0; i < 3; i++)
{
if (a[i] != b[i])
return false;
}
return true;
}
public static bool operator !=(int3 a, int3 b)
{
return !(a == b);
}
public static int3 roll3(int3 a)
{
int tmp = a[0];
a[0] = a[1];
a[1] = a[2];
a[2] = tmp;
return a;
}
public static bool isa(int3 a, int3 b)
{
return (a == b || roll3(a) == b || a == roll3(b));
}
public static bool b2b(int3 a, int3 b)
{
return isa(a, new int3(b[2], b[1], b[0]));
}
}
}

View File

@ -0,0 +1,66 @@
/* The MIT License
*
* Copyright (c) 2010 Intel Corporation.
* All rights reserved.
*
* Based on the convexdecomposition library from
* <http://codesuppository.googlecode.com> by John W. Ratcliff and Stan Melax.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
using System;
namespace OpenSim.Region.Physics.ConvexDecompositionDotNet
{
public class int4
{
public int x;
public int y;
public int z;
public int w;
public int4()
{
}
public int4(int _x, int _y, int _z, int _w)
{
x = _x;
y = _y;
z = _z;
w = _w;
}
public int this[int i]
{
get
{
switch (i)
{
case 0: return x;
case 1: return y;
case 2: return z;
case 3: return w;
}
throw new ArgumentOutOfRangeException();
}
}
}
}

View File

@ -0,0 +1,28 @@
ConvexDecompositionDotNet
-------------------------
The MIT License
Copyright (c) 2010 Intel Corporation.
All rights reserved.
Based on the convexdecomposition library from
<http://codesuppository.googlecode.com> by John W. Ratcliff and Stan Melax.
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.

View File

@ -601,6 +601,64 @@
</Files>
</Project>
<Project frameworkVersion="v3_5" name="OpenSim.Region.Physics.BulletSPlugin" path="OpenSim/Region/Physics/BulletSPlugin" type="Library">
<Configuration name="Debug">
<Options>
<OutputPath>../../../../bin/Physics/</OutputPath>
</Options>
</Configuration>
<Configuration name="Release">
<Options>
<OutputPath>../../../../bin/Physics/</OutputPath>
</Options>
</Configuration>
<ReferencePath>../../../../bin/</ReferencePath>
<Reference name="System"/>
<Reference name="System.Core"/>
<Reference name="System.Xml"/>
<Reference name="OpenMetaverseTypes" path="../../../../bin/"/>
<Reference name="Nini.dll" path="../../../../bin/"/>
<Reference name="OpenSim.Framework"/>
<Reference name="OpenSim.Region.Framework"/>
<Reference name="OpenSim.Region.CoreModules"/>
<Reference name="OpenSim.Framework.Console"/>
<Reference name="OpenSim.Region.Physics.Manager"/>
<Reference name="OpenSim.Region.Physics.ConvexDecompositionDotNet"/>
<Reference name="log4net.dll" path="../../../../bin/"/>
<Files>
<Match pattern="*.cs" recurse="true">
<Exclude name="Tests" pattern="Tests"/>
</Match>
</Files>
</Project>
<Project frameworkVersion="v3_5" name="OpenSim.Region.Physics.ConvexDecompositionDotNet" path="OpenSim/Region/Physics/ConvexDecompositionDotNet" type="Library">
<Configuration name="Debug">
<Options>
<OutputPath>../../../../bin/Physics/</OutputPath>
</Options>
</Configuration>
<Configuration name="Release">
<Options>
<OutputPath>../../../../bin/Physics/</OutputPath>
</Options>
</Configuration>
<ReferencePath>../../../../bin/</ReferencePath>
<Reference name="System"/>
<Reference name="System.Core"/>
<Reference name="System.Data"/>
<Reference name="System.Xml"/>
<Files>
<Match pattern="*.cs" recurse="true">
<Exclude name="Tests" pattern="Tests"/>
</Match>
</Files>
</Project>
<Project frameworkVersion="v3_5" name="OpenSim.Region.Physics.Meshing" path="OpenSim/Region/Physics/Meshing" type="Library">
<Configuration name="Debug">
<Options>