Merge branch 'dev' into dev_attachment

dsg
Huaiyu (Kitty) Liu 2011-05-19 13:46:35 -07:00
commit ef4caa2c75
37 changed files with 7935 additions and 7 deletions

View File

@ -342,7 +342,7 @@ namespace OpenSim.Region.CoreModules.RegionSync.RegionSyncModule
{ {
UUID uuid = data["uuid"].AsUUID(); UUID uuid = data["uuid"].AsUUID();
string actorID = data["actorID"].AsString(); string actorID = data["actorID"].AsString();
m_log.DebugFormat("{0}: HandlPhysUpdateAttributes for {1}", LogHeader, uuid); // m_log.DebugFormat("{0}: HandlPhysUpdateAttributes for {1}", LogHeader, uuid);
PhysicsActor pa = FindPhysicsActor(uuid); PhysicsActor pa = FindPhysicsActor(uuid);
if (pa != null) if (pa != null)
{ {

View File

@ -373,7 +373,7 @@ namespace OpenSim.Region.CoreModules.RegionSync.RegionSyncModule
pa.Kinematic = data["kinematic"].AsBoolean(); // receive?? pa.Kinematic = data["kinematic"].AsBoolean(); // receive??
pa.Buoyancy = (float)(data["buoyancy"].AsReal()); pa.Buoyancy = (float)(data["buoyancy"].AsReal());
pa.CollidingGround = data["isCollidingGround"].AsBoolean(); pa.CollidingGround = data["isCollidingGround"].AsBoolean();
pa.IsColliding = data["isCollidingGround"].AsBoolean(); pa.IsColliding = data["isColliding"].AsBoolean();
pa.ChangingActorID = actorID; pa.ChangingActorID = actorID;
pa.RequestPhysicsterseUpdate(); // tell the system the values have changed pa.RequestPhysicsterseUpdate(); // tell the system the values have changed
@ -431,8 +431,8 @@ namespace OpenSim.Region.CoreModules.RegionSync.RegionSyncModule
data["isPhysical"] = OSD.FromBoolean(pa.IsPhysical); data["isPhysical"] = OSD.FromBoolean(pa.IsPhysical);
data["flying"] = OSD.FromBoolean(pa.Flying); data["flying"] = OSD.FromBoolean(pa.Flying);
data["buoyancy"] = OSD.FromReal(pa.Buoyancy); data["buoyancy"] = OSD.FromReal(pa.Buoyancy);
// data["isColliding"] = OSD.FromBoolean(pa.IsColliding); data["isColliding"] = OSD.FromBoolean(pa.IsColliding);
// data["isCollidingGround"] = OSD.FromBoolean(pa.CollidingGround); data["isCollidingGround"] = OSD.FromBoolean(pa.CollidingGround);
RegionSyncMessage rsm = new RegionSyncMessage(RegionSyncMessage.MsgType.PhysUpdateAttributes, RegionSyncMessage rsm = new RegionSyncMessage(RegionSyncMessage.MsgType.PhysUpdateAttributes,
OSDParser.SerializeJsonString(data)); OSDParser.SerializeJsonString(data));

View File

@ -1751,7 +1751,8 @@ namespace OpenSim.Region.Framework.Scenes
// Check that we have a physics actor or we're sitting on something // Check that we have a physics actor or we're sitting on something
if (sp.ParentID == 0 && sp.PhysicsActor != null || sp.ParentID != 0) if (sp.ParentID == 0 && sp.PhysicsActor != null || sp.ParentID != 0)
{ {
sp.CheckForBorderCrossing(); if(!sp.IsSyncedAvatar)
sp.CheckForBorderCrossing();
} }
} }
}); });

View File

@ -1627,6 +1627,7 @@ namespace OpenSim.Region.Framework.Scenes
if (!isPhantom && !IsAttachment && !(Shape.PathCurve == (byte) Extrusion.Flexible)) if (!isPhantom && !IsAttachment && !(Shape.PathCurve == (byte) Extrusion.Flexible))
{ {
PhysActor = m_parentGroup.Scene.PhysicsScene.AddPrimShape( PhysActor = m_parentGroup.Scene.PhysicsScene.AddPrimShape(
LocalId,
string.Format("{0}/{1}", Name, UUID), string.Format("{0}/{1}", Name, UUID),
Shape, Shape,
AbsolutePosition, AbsolutePosition,
@ -2794,7 +2795,12 @@ namespace OpenSim.Region.Framework.Scenes
//m_parentGroup.RootPart.m_groupPosition = newpos; //m_parentGroup.RootPart.m_groupPosition = newpos;
} }
//ScheduleTerseUpdate(); //ScheduleTerseUpdate();
ScheduleTerseUpdate(new List<SceneObjectPartSyncProperties>(){SceneObjectPartSyncProperties.Position}); ScheduleTerseUpdate(new List<SceneObjectPartSyncProperties>(){
SceneObjectPartSyncProperties.Position,
SceneObjectPartSyncProperties.Orientation,
SceneObjectPartSyncProperties.Velocity,
SceneObjectPartSyncProperties.RotationalVelocity
});
//SendTerseUpdateToAllClients(); //SendTerseUpdateToAllClients();
} }
@ -4490,6 +4496,7 @@ namespace OpenSim.Region.Framework.Scenes
{ {
// It's not phantom anymore. So make sure the physics engine get's knowledge of it // It's not phantom anymore. So make sure the physics engine get's knowledge of it
PhysActor = m_parentGroup.Scene.PhysicsScene.AddPrimShape( PhysActor = m_parentGroup.Scene.PhysicsScene.AddPrimShape(
LocalId,
string.Format("{0}/{1}", Name, UUID), string.Format("{0}/{1}", Name, UUID),
Shape, Shape,
AbsolutePosition, AbsolutePosition,

View File

@ -3405,7 +3405,7 @@ namespace OpenSim.Region.Framework.Scenes
Vector3 pVec = AbsolutePosition; Vector3 pVec = AbsolutePosition;
// Old bug where the height was in centimeters instead of meters // Old bug where the height was in centimeters instead of meters
m_physicsActor = scene.AddAvatar(Firstname + "." + Lastname, pVec, m_physicsActor = scene.AddAvatar(LocalId, Firstname + "." + Lastname, pVec,
new Vector3(0f, 0f, m_appearance.AvatarHeight), isFlying); new Vector3(0f, 0f, m_appearance.AvatarHeight), isFlying);
scene.AddPhysicsActorTaint(m_physicsActor); scene.AddPhysicsActorTaint(m_physicsActor);

View File

@ -66,6 +66,11 @@ namespace OpenSim.Region.Physics.Manager
public abstract PhysicsActor AddAvatar(string avName, Vector3 position, Vector3 size, bool isFlying); public abstract PhysicsActor AddAvatar(string avName, Vector3 position, Vector3 size, bool isFlying);
public virtual PhysicsActor AddAvatar(uint localID, string avName, Vector3 position, Vector3 size, bool isFlying)
{
return AddAvatar(avName, position, size, isFlying);
}
public abstract void RemoveAvatar(PhysicsActor actor); public abstract void RemoveAvatar(PhysicsActor actor);
public abstract void RemovePrim(PhysicsActor prim); public abstract void RemovePrim(PhysicsActor prim);
@ -75,6 +80,12 @@ namespace OpenSim.Region.Physics.Manager
public abstract PhysicsActor AddPrimShape(string primName, PrimitiveBaseShape pbs, Vector3 position, public abstract PhysicsActor AddPrimShape(string primName, PrimitiveBaseShape pbs, Vector3 position,
Vector3 size, Quaternion rotation, bool isPhysical); Vector3 size, Quaternion rotation, bool isPhysical);
public virtual PhysicsActor AddPrimShape(uint localId, string primName, PrimitiveBaseShape pbs, Vector3 position,
Vector3 size, Quaternion rotation, bool isPhysical)
{
return AddPrimShape(primName, pbs, position, size, rotation, isPhysical);
}
public virtual float TimeDilation public virtual float TimeDilation
{ {
get { return 1.0f; } get { return 1.0f; }

View File

@ -0,0 +1,413 @@
/*
* Copyright (c) 2011 Intel Corporation
*
* 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 Intel Corporation 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 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;
_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.Flying = isFlying ? ShapeData.numericTrue : ShapeData.numericFalse;
shapeData.Dynamic = ShapeData.numericFalse;
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()
{
BulletSimAPI.SetObjectFlying(_scene.WorldID, LocalID, _flying);
});
}
}
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;
}
else
{
m_log.WarnFormat("{0}: Got a NaN force applied to a Character", LogHeader);
}
_scene.TaintedObject(delegate()
{
BulletSimAPI.SetObjectForce(_scene.WorldID, _localID, _force);
});
//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;
}
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);
if (_subscribedEventsMs == 0) return; // don't want collisions
// The following says we're colliding this simulation step
_collidingStep = _scene.SimulationStep;
if (collidingWith == BSScene.TERRAIN_ID || collidingWith == BSScene.GROUNDPLANE_ID)
{
_collidingGroundStep = _scene.SimulationStep;
}
Dictionary<uint, ContactPoint> contactPoints = new Dictionary<uint, ContactPoint>();
contactPoints.Add(collidingWith, new ContactPoint(contactPoint, contactNormal, pentrationDepth));
CollisionEventUpdate args = new CollisionEventUpdate(LocalID, (int)type, 1, contactPoints);
base.SendCollisionUpdate(args);
}
}
}

View File

@ -0,0 +1,67 @@
/*
* Copyright (c) Intel Corporation
*
* 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 Intel Corporation nor the
* names of its contributors may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
using System;
using System.Collections.Generic;
using OpenSim.Framework;
using OpenSim.Region.Physics.Manager;
using OpenMetaverse;
namespace OpenSim.Region.Physics.BulletSPlugin
{
public class BSPlugin : IPhysicsPlugin
{
//private static readonly log4net.ILog m_log = log4net.LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType);
private BSScene _mScene;
public BSPlugin()
{
}
public bool Init()
{
return true;
}
public PhysicsScene GetScene(String sceneIdentifier)
{
if (_mScene == null)
{
_mScene = new BSScene(sceneIdentifier);
}
return (_mScene);
}
public string GetName()
{
return ("BulletSim");
}
public void Dispose()
{
}
}
}

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,471 @@
/*
* Copyright (c) 2011 Intel Corporation
*
* 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 Intel Corporation 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 (both BSScene and BSPrim)
// Does NeedsMeshing() really need to exclude all the different shapes?
// 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)
// Need three states for objects: sense and report collisions, have physical effects, affects other objects
// LinkSets
// Freeing of memory of linksets in BulletSim::DestroyObject
// Should prim.link() and prim.delink() be done at taint time?
// Pass collision enable flags to BulletSim code so collisions are not reported up unless they are really needed
// Set child prims phantom since the physicality is handled by the parent prim
// Linked children need rotation relative to parent (passed as world rotation)
//
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 float[] m_heightMap;
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 delegate void TaintCallback();
private List<TaintCallback> _taintedObjects;
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);
}
}
// 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, 1000f));
}
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.
// m_log.DebugFormat("{0}: AddPrimShape2: creating mesh", LogHeader);
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;
}
public override void AddPhysicsActorTaint(PhysicsActor prim) { }
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();
// 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
if (updatedEntityCount > 0)
{
updatedEntities = new IntPtr[updatedEntityCount];
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);
if (m_avatars.ContainsKey(entprop.ID))
{
BSCharacter actor = m_avatars[entprop.ID];
actor.UpdateProperties(entprop);
}
if (m_prims.ContainsKey(entprop.ID))
{
BSPrim prim = m_prims[entprop.ID];
prim.UpdateProperties(entprop);
}
}
}
return 11f; // returns frames per second
}
// 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 (m_avatars.ContainsKey(collidingWith))
type = ActorTypes.Agent;
else if (collidingWith == TERRAIN_ID || collidingWith == GROUNDPLANE_ID)
type = ActorTypes.Ground;
if (m_prims.ContainsKey(localID))
{
BSPrim prim = m_prims[localID];
prim.Collide(collidingWith, type, Vector3.Zero, Vector3.UnitZ, 0.01f);
return;
}
if (m_avatars.ContainsKey(localID))
{
BSCharacter actor = m_avatars[localID];
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 override void SetWaterLevel(float baseheight) { }
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)
{
// do we need to lock?
_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()
{
// swizzle a new list into the list location so we can process what's there
List<TaintCallback> newList = new List<TaintCallback>();
List<TaintCallback> oldList = (List<TaintCallback>)Interlocked.Exchange(ref _taintedObjects, newList);
foreach (TaintCallback callback in oldList)
{
try
{
callback();
}
catch (Exception e)
{
m_log.ErrorFormat("{0}: ProcessTaints: Exception: {1}", LogHeader, e);
}
}
oldList.Clear();
}
}
}

View File

@ -0,0 +1,171 @@
/*
Copyright (c) 2011, Intel Corporation
All rights reserved.
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 Intel Corporation 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 COPYRIGHT HOLDERS AND CONTRIBUTORS "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 COPYRIGHT OWNER OR 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 System.UInt64 MeshKey;
public int Collidable;
public int Flying;
public float Friction;
public int Dynamic;
// 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 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 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 SetObjectFlying(uint worldID, uint id, bool flying);
[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
public static extern bool HasObject(uint worldID, uint id);
[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
public static extern bool DestroyObject(uint worldID, uint id);
[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
public static extern SweepHit ConvexSweepTest(uint worldID, uint id, Vector3 to, float extraMargin);
[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
public static extern RaycastHit RayTest(uint worldID, uint id, Vector3 from, Vector3 to);
[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
public static extern Vector3 RecoverFromPenetration(uint worldID, uint id);
// Log a debug message
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
public delegate void DebugLogCallback([MarshalAs(UnmanagedType.LPStr)]string msg);
[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
public static extern void SetDebugLogCallback(DebugLogCallback callback);
}
}

View File

@ -0,0 +1,32 @@
<Project frameworkVersion="v3_5" name="OpenSim.Region.Physics.BulletSPlugin" path="addon-modules/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>

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

File diff suppressed because it is too large Load Diff

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -0,0 +1,24 @@
<Project frameworkVersion="v3_5" name="OpenSim.Region.Physics.ConvexDecompositionDotNet" path="addon-modules/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>

BIN
bin/BulletSim.dll Executable file

Binary file not shown.

0
runprebuild2010.bat Normal file → Executable file
View File