BulletSim initial checkin
parent
7819b4a794
commit
302d72701d
|
@ -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);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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
|
@ -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
|
||||
}
|
||||
}
|
|
@ -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);
|
||||
}
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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); });
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
}
|
|
@ -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
|
@ -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.
|
|
@ -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));
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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")]
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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.
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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();
|
||||
}
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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]));
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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.
|
58
prebuild.xml
58
prebuild.xml
|
@ -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>
|
||||
|
|
Loading…
Reference in New Issue