* Moves the Meshmerizer to a separate plugin

* Experimental.   Linux Prebuild needs testing.
* One more update after this to remove the ODEMeshing directory....
afrisby
Teravus Ovares 2007-11-10 19:13:52 +00:00
parent 43ea37b5a0
commit cb07ba0d68
18 changed files with 1996 additions and 68 deletions

View File

@ -54,6 +54,7 @@ namespace OpenSim
private const string DEFAULT_PRIM_BACKUP_FILENAME = "prim-backup.xml"; private const string DEFAULT_PRIM_BACKUP_FILENAME = "prim-backup.xml";
public string m_physicsEngine; public string m_physicsEngine;
public string m_meshEngineName;
public string m_scriptEngine; public string m_scriptEngine;
public bool m_sandbox; public bool m_sandbox;
public bool user_accounts; public bool user_accounts;
@ -210,6 +211,7 @@ namespace OpenSim
{ {
m_sandbox = !startupConfig.GetBoolean("gridmode", false); m_sandbox = !startupConfig.GetBoolean("gridmode", false);
m_physicsEngine = startupConfig.GetString("physics", "basicphysics"); m_physicsEngine = startupConfig.GetString("physics", "basicphysics");
m_meshEngineName = startupConfig.GetString("meshing", "Meshmerizer");
m_verbose = startupConfig.GetBoolean("verbose", true); m_verbose = startupConfig.GetBoolean("verbose", true);
m_permissions = startupConfig.GetBoolean("serverside_object_permissions", false); m_permissions = startupConfig.GetBoolean("serverside_object_permissions", false);
@ -404,7 +406,7 @@ namespace OpenSim
protected override PhysicsScene GetPhysicsScene() protected override PhysicsScene GetPhysicsScene()
{ {
return GetPhysicsScene(m_physicsEngine); return GetPhysicsScene(m_physicsEngine, m_meshEngineName);
} }
private class SimStatusHandler : IStreamedRequestHandler private class SimStatusHandler : IStreamedRequestHandler
@ -767,4 +769,4 @@ namespace OpenSim
#endregion #endregion
} }
} }

View File

@ -29,6 +29,7 @@ using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Net; using System.Net;
using libsecondlife; using libsecondlife;
using Nini.Config;
using OpenSim.Framework; using OpenSim.Framework;
using OpenSim.Framework.Communications; using OpenSim.Framework.Communications;
using OpenSim.Framework.Communications.Cache; using OpenSim.Framework.Communications.Cache;
@ -89,12 +90,12 @@ namespace OpenSim.Region.ClientStack
protected abstract PhysicsScene GetPhysicsScene(); protected abstract PhysicsScene GetPhysicsScene();
protected abstract StorageManager CreateStorageManager(RegionInfo regionInfo); protected abstract StorageManager CreateStorageManager(RegionInfo regionInfo);
protected PhysicsScene GetPhysicsScene(string engine) protected PhysicsScene GetPhysicsScene(string engine, string meshEngine)
{ {
PhysicsPluginManager physicsPluginManager; PhysicsPluginManager physicsPluginManager;
physicsPluginManager = new PhysicsPluginManager(); physicsPluginManager = new PhysicsPluginManager();
physicsPluginManager.LoadPlugins(); physicsPluginManager.LoadPlugins();
return physicsPluginManager.GetPhysicsScene(engine); return physicsPluginManager.GetPhysicsScene(engine, meshEngine);
} }
protected Scene SetupScene(RegionInfo regionInfo, out UDPServer udpServer) protected Scene SetupScene(RegionInfo regionInfo, out UDPServer udpServer)
@ -150,4 +151,4 @@ namespace OpenSim.Region.ClientStack
protected abstract Scene CreateScene(RegionInfo regionInfo, StorageManager storageManager, protected abstract Scene CreateScene(RegionInfo regionInfo, StorageManager storageManager,
AgentCircuitManager circuitManager); AgentCircuitManager circuitManager);
} }
} }

View File

@ -182,7 +182,7 @@ namespace SimpleApp
protected override PhysicsScene GetPhysicsScene() protected override PhysicsScene GetPhysicsScene()
{ {
return GetPhysicsScene("basicphysics"); return GetPhysicsScene("basicphysics", "Meshmerizer");
} }
#region conscmd_callback Members #region conscmd_callback Members
@ -206,4 +206,4 @@ namespace SimpleApp
app.Run(); app.Run();
} }
} }
} }

View File

@ -70,6 +70,11 @@ namespace OpenSim.Region.Physics.BasicPhysicsPlugin
{ {
} }
public override void Initialise(IMesher meshmerizer)
{
// Does nothing right now
}
public override PhysicsActor AddAvatar(string avName, PhysicsVector position) public override PhysicsActor AddAvatar(string avName, PhysicsVector position)
{ {
BasicActor act = new BasicActor(); BasicActor act = new BasicActor();
@ -274,4 +279,4 @@ namespace OpenSim.Region.Physics.BasicPhysicsPlugin
{ {
} }
} }
} }

View File

@ -64,6 +64,7 @@ using System;
using System.Collections.Generic; using System.Collections.Generic;
using MonoXnaCompactMaths; using MonoXnaCompactMaths;
using OpenSim.Framework; using OpenSim.Framework;
using OpenSim.Framework.Console;
using OpenSim.Region.Physics.Manager; using OpenSim.Region.Physics.Manager;
using XnaDevRu.BulletX; using XnaDevRu.BulletX;
using XnaDevRu.BulletX.Dynamics; using XnaDevRu.BulletX.Dynamics;
@ -74,15 +75,6 @@ using BoxShape=XnaDevRu.BulletX.BoxShape;
namespace OpenSim.Region.Physics.BulletXPlugin namespace OpenSim.Region.Physics.BulletXPlugin
{ {
/// <summary>
/// This class is only here for compilations reasons
/// </summary>
public class Mesh
{
public Mesh()
{
}
}
/// <summary> /// <summary>
/// BulletXConversions are called now BulletXMaths /// BulletXConversions are called now BulletXMaths
@ -268,6 +260,65 @@ namespace OpenSim.Region.Physics.BulletXPlugin
} }
} }
// Class to detect and debug collisions
// Mainly used for debugging purposes
class CollisionDispatcherLocal : CollisionDispatcher
{
BulletXScene relatedScene;
public CollisionDispatcherLocal(BulletXScene s)
: base()
{
relatedScene=s;
}
public override bool NeedsCollision(CollisionObject bodyA, CollisionObject bodyB)
{
RigidBody rb;
BulletXCharacter bxcA=null;
BulletXPrim bxpA = null;
Type t = bodyA.GetType();
if (t==typeof(RigidBody)) {
rb = (RigidBody)bodyA;
relatedScene._characters.TryGetValue(rb, out bxcA);
relatedScene._prims.TryGetValue(rb, out bxpA);
}
String nameA;
if (bxcA != null)
nameA = bxcA._name;
else if (bxpA != null)
nameA = bxpA._name;
else
nameA = "null";
BulletXCharacter bxcB = null;
BulletXPrim bxpB = null;
t = bodyB.GetType();
if (t == typeof(RigidBody))
{
rb = (RigidBody)bodyB;
relatedScene._characters.TryGetValue(rb, out bxcB);
relatedScene._prims.TryGetValue(rb, out bxpB);
}
String nameB;
if (bxcB != null)
nameB = bxcB._name;
else if (bxpB != null)
nameB = bxpB._name;
else
nameB = "null";
bool needsCollision=base.NeedsCollision(bodyA, bodyB);
MainLog.Instance.Debug("BulletX", "A collision was detected between {0} and {1} --> {2}", nameA, nameB, needsCollision);
return needsCollision;
}
}
/// <summary> /// <summary>
/// PhysicsScene Class for BulletX /// PhysicsScene Class for BulletX
/// </summary> /// </summary>
@ -294,8 +345,11 @@ namespace OpenSim.Region.Physics.BulletXPlugin
private const int simulationSubSteps = 10; private const int simulationSubSteps = 10;
//private float[] _heightmap; //private float[] _heightmap;
private BulletXPlanet _simFlatPlanet; private BulletXPlanet _simFlatPlanet;
private List<BulletXCharacter> _characters = new List<BulletXCharacter>(); internal Dictionary<RigidBody, BulletXCharacter> _characters = new Dictionary<RigidBody, BulletXCharacter>();
private List<BulletXPrim> _prims = new List<BulletXPrim>(); internal Dictionary<RigidBody, BulletXPrim> _prims = new Dictionary<RigidBody, BulletXPrim>();
public IMesher mesher;
public static float Gravity public static float Gravity
{ {
@ -334,7 +388,7 @@ namespace OpenSim.Region.Physics.BulletXPlugin
public BulletXScene() public BulletXScene()
{ {
cDispatcher = new CollisionDispatcher(); cDispatcher = new CollisionDispatcherLocal(this);
Vector3 worldMinDim = new Vector3((float) minXY, (float) minXY, (float) minZ); Vector3 worldMinDim = new Vector3((float) minXY, (float) minXY, (float) minZ);
Vector3 worldMaxDim = new Vector3((float) maxXY, (float) maxXY, (float) maxZ); Vector3 worldMaxDim = new Vector3((float) maxXY, (float) maxXY, (float) maxZ);
opCache = new AxisSweep3(worldMinDim, worldMaxDim, maxHandles); opCache = new AxisSweep3(worldMinDim, worldMaxDim, maxHandles);
@ -348,6 +402,12 @@ namespace OpenSim.Region.Physics.BulletXPlugin
//this._heightmap = new float[65536]; //this._heightmap = new float[65536];
} }
public override void Initialise(IMesher meshmerizer)
{
mesher = meshmerizer;
}
public override PhysicsActor AddAvatar(string avName, PhysicsVector position) public override PhysicsActor AddAvatar(string avName, PhysicsVector position)
{ {
PhysicsVector pos = new PhysicsVector(); PhysicsVector pos = new PhysicsVector();
@ -358,7 +418,7 @@ namespace OpenSim.Region.Physics.BulletXPlugin
lock (BulletXLock) lock (BulletXLock)
{ {
newAv = new BulletXCharacter(avName, this, pos); newAv = new BulletXCharacter(avName, this, pos);
_characters.Add(newAv); _characters.Add(newAv.RigidBody, newAv);
} }
return newAv; return newAv;
} }
@ -379,7 +439,7 @@ namespace OpenSim.Region.Physics.BulletXPlugin
((BulletXCharacter) actor).RigidBody.ActivationState = ActivationState.DisableSimulation; ((BulletXCharacter) actor).RigidBody.ActivationState = ActivationState.DisableSimulation;
AddForgottenRigidBody(((BulletXCharacter) actor).RigidBody); AddForgottenRigidBody(((BulletXCharacter) actor).RigidBody);
} }
_characters.Remove((BulletXCharacter) actor); _characters.Remove(((BulletXCharacter)actor).RigidBody);
} }
GC.Collect(); GC.Collect();
} }
@ -405,7 +465,7 @@ namespace OpenSim.Region.Physics.BulletXPlugin
} }
else else
{ {
Mesh mesh = null; IMesh mesh = mesher.CreateMesh(primName, pbs, size);
result = AddPrim(primName, position, size, rotation, mesh, pbs, isPhysical); result = AddPrim(primName, position, size, rotation, mesh, pbs, isPhysical);
} }
break; break;
@ -419,13 +479,13 @@ namespace OpenSim.Region.Physics.BulletXPlugin
} }
public PhysicsActor AddPrim(String name, PhysicsVector position, PhysicsVector size, AxiomQuaternion rotation, public PhysicsActor AddPrim(String name, PhysicsVector position, PhysicsVector size, AxiomQuaternion rotation,
Mesh mesh, PrimitiveBaseShape pbs, bool isPhysical) IMesh mesh, PrimitiveBaseShape pbs, bool isPhysical)
{ {
BulletXPrim newPrim = null; BulletXPrim newPrim = null;
lock (BulletXLock) lock (BulletXLock)
{ {
newPrim = new BulletXPrim(name, this, position, size, rotation, mesh, pbs, isPhysical); newPrim = new BulletXPrim(name, this, position, size, rotation, mesh, pbs, isPhysical);
_prims.Add(newPrim); _prims.Add(newPrim.RigidBody, newPrim);
} }
return newPrim; return newPrim;
} }
@ -446,7 +506,7 @@ namespace OpenSim.Region.Physics.BulletXPlugin
((BulletXPrim) prim).RigidBody.ActivationState = ActivationState.DisableSimulation; ((BulletXPrim) prim).RigidBody.ActivationState = ActivationState.DisableSimulation;
AddForgottenRigidBody(((BulletXPrim) prim).RigidBody); AddForgottenRigidBody(((BulletXPrim) prim).RigidBody);
} }
_prims.Remove((BulletXPrim) prim); _prims.Remove(((BulletXPrim) prim).RigidBody);
} }
GC.Collect(); GC.Collect();
} }
@ -470,11 +530,11 @@ namespace OpenSim.Region.Physics.BulletXPlugin
private void MoveAllObjects(float timeStep) private void MoveAllObjects(float timeStep)
{ {
foreach (BulletXCharacter actor in _characters) foreach (BulletXCharacter actor in _characters.Values)
{ {
actor.Move(timeStep); actor.Move(timeStep);
} }
foreach (BulletXPrim prim in _prims) foreach (BulletXPrim prim in _prims.Values)
{ {
} }
} }
@ -482,14 +542,14 @@ namespace OpenSim.Region.Physics.BulletXPlugin
private void ValidateHeightForAll() private void ValidateHeightForAll()
{ {
float _height; float _height;
foreach (BulletXCharacter actor in _characters) foreach (BulletXCharacter actor in _characters.Values)
{ {
//_height = HeightValue(actor.RigidBodyPosition); //_height = HeightValue(actor.RigidBodyPosition);
_height = _simFlatPlanet.HeightValue(actor.RigidBodyPosition); _height = _simFlatPlanet.HeightValue(actor.RigidBodyPosition);
actor.ValidateHeight(_height); actor.ValidateHeight(_height);
//if (_simFlatPlanet.heightIsNotValid(actor.RigidBodyPosition, out _height)) actor.ValidateHeight(_height); //if (_simFlatPlanet.heightIsNotValid(actor.RigidBodyPosition, out _height)) actor.ValidateHeight(_height);
} }
foreach (BulletXPrim prim in _prims) foreach (BulletXPrim prim in _prims.Values)
{ {
//_height = HeightValue(prim.RigidBodyPosition); //_height = HeightValue(prim.RigidBodyPosition);
_height = _simFlatPlanet.HeightValue(prim.RigidBodyPosition); _height = _simFlatPlanet.HeightValue(prim.RigidBodyPosition);
@ -510,11 +570,11 @@ namespace OpenSim.Region.Physics.BulletXPlugin
{ {
//UpdatePosition > UpdateKinetics. //UpdatePosition > UpdateKinetics.
//Not only position will be updated, also velocity cause acceleration. //Not only position will be updated, also velocity cause acceleration.
foreach (BulletXCharacter actor in _characters) foreach (BulletXCharacter actor in _characters.Values)
{ {
actor.UpdateKinetics(); actor.UpdateKinetics();
} }
foreach (BulletXPrim prim in _prims) foreach (BulletXPrim prim in _prims.Values)
{ {
prim.UpdateKinetics(); prim.UpdateKinetics();
} }
@ -646,9 +706,11 @@ namespace OpenSim.Region.Physics.BulletXPlugin
protected PhysicsVector m_rotationalVelocity = PhysicsVector.Zero; protected PhysicsVector m_rotationalVelocity = PhysicsVector.Zero;
protected RigidBody rigidBody; protected RigidBody rigidBody;
private Boolean iscolliding = false; private Boolean iscolliding = false;
internal string _name;
public BulletXActor() public BulletXActor(String name)
{ {
_name = name;
} }
public override PhysicsVector Position public override PhysicsVector Position
@ -847,6 +909,7 @@ namespace OpenSim.Region.Physics.BulletXPlugin
} }
public BulletXCharacter(String avName, BulletXScene parent_scene, PhysicsVector pos, PhysicsVector velocity, public BulletXCharacter(String avName, BulletXScene parent_scene, PhysicsVector pos, PhysicsVector velocity,
PhysicsVector size, PhysicsVector acceleration, AxiomQuaternion orientation) PhysicsVector size, PhysicsVector acceleration, AxiomQuaternion orientation)
: base(avName)
{ {
//This fields will be removed. They're temporal //This fields will be removed. They're temporal
float _sizeX = 0.5f; float _sizeX = 0.5f;
@ -1016,14 +1079,15 @@ namespace OpenSim.Region.Physics.BulletXPlugin
private bool m_lastUpdateSent = false; private bool m_lastUpdateSent = false;
public BulletXPrim(String primName, BulletXScene parent_scene, PhysicsVector pos, PhysicsVector size, public BulletXPrim(String primName, BulletXScene parent_scene, PhysicsVector pos, PhysicsVector size,
AxiomQuaternion rotation, Mesh mesh, PrimitiveBaseShape pbs, bool isPhysical) AxiomQuaternion rotation, IMesh mesh, PrimitiveBaseShape pbs, bool isPhysical)
: this(primName, parent_scene, pos, new PhysicsVector(), size, new PhysicsVector(), rotation, mesh, pbs, isPhysical) : this(primName, parent_scene, pos, new PhysicsVector(), size, new PhysicsVector(), rotation, mesh, pbs, isPhysical)
{ {
} }
public BulletXPrim(String primName, BulletXScene parent_scene, PhysicsVector pos, PhysicsVector velocity, public BulletXPrim(String primName, BulletXScene parent_scene, PhysicsVector pos, PhysicsVector velocity,
PhysicsVector size, PhysicsVector size,
PhysicsVector acceleration, AxiomQuaternion rotation, Mesh mesh, PrimitiveBaseShape pbs, PhysicsVector acceleration, AxiomQuaternion rotation, IMesh mesh, PrimitiveBaseShape pbs,
bool isPhysical) bool isPhysical)
: base(primName)
{ {
if ((size.X == 0) || (size.Y == 0) || (size.Z == 0)) throw new Exception("Size 0"); if ((size.X == 0) || (size.Y == 0) || (size.Z == 0)) throw new Exception("Size 0");
if (rotation.Norm == 0f) rotation = AxiomQuaternion.Identity; if (rotation.Norm == 0f) rotation = AxiomQuaternion.Identity;
@ -1037,7 +1101,7 @@ namespace OpenSim.Region.Physics.BulletXPlugin
_parent_scene = parent_scene; _parent_scene = parent_scene;
CreateRigidBody(parent_scene, pos, size); CreateRigidBody(parent_scene, mesh, pos, size);
} }
public override PhysicsVector Position public override PhysicsVector Position
@ -1191,7 +1255,7 @@ namespace OpenSim.Region.Physics.BulletXPlugin
} }
#region Methods for updating values of RigidBody #region Methods for updating values of RigidBody
internal protected void CreateRigidBody(BulletXScene parent_scene, PhysicsVector pos, PhysicsVector size) internal protected void CreateRigidBody(BulletXScene parent_scene, IMesh mesh, PhysicsVector pos, PhysicsVector size)
{ {
//For RigidBody Constructor. The next values might change //For RigidBody Constructor. The next values might change
float _linearDamping = 0.0f; float _linearDamping = 0.0f;
@ -1204,7 +1268,26 @@ namespace OpenSim.Region.Physics.BulletXPlugin
{ {
_startTransform.Translation = BulletXMaths.PhysicsVectorToXnaVector3(pos); _startTransform.Translation = BulletXMaths.PhysicsVectorToXnaVector3(pos);
//For now all prims are boxes //For now all prims are boxes
CollisionShape _collisionShape = new XnaDevRu.BulletX.BoxShape(BulletXMaths.PhysicsVectorToXnaVector3(size) / 2.0f); CollisionShape _collisionShape;
if (mesh == null)
{
_collisionShape = new XnaDevRu.BulletX.BoxShape(BulletXMaths.PhysicsVectorToXnaVector3(size) / 2.0f);
} else {
int iVertexCount = mesh.getVertexList().Count;
int[] indices = mesh.getIndexListAsInt();
Vector3[] v3Vertices = new Vector3[iVertexCount];
for (int i = 0; i < iVertexCount; i++)
{
PhysicsVector v=mesh.getVertexList()[i];
if (v != null) // Note, null has special meaning. See meshing code for details
v3Vertices[i] = BulletXMaths.PhysicsVectorToXnaVector3(v);
else
v3Vertices[i] = MonoXnaCompactMaths.Vector3.Zero;
}
TriangleIndexVertexArray triMesh = new TriangleIndexVertexArray(indices, v3Vertices);
_collisionShape = new XnaDevRu.BulletX.TriangleMeshShape(triMesh);
}
DefaultMotionState _motionState = new DefaultMotionState(_startTransform, _centerOfMassOffset); DefaultMotionState _motionState = new DefaultMotionState(_startTransform, _centerOfMassOffset);
Vector3 _localInertia = new Vector3(); Vector3 _localInertia = new Vector3();
if (_physical) _collisionShape.CalculateLocalInertia(Mass, out _localInertia); //Always when mass > 0 if (_physical) _collisionShape.CalculateLocalInertia(Mass, out _localInertia); //Always when mass > 0
@ -1231,7 +1314,7 @@ namespace OpenSim.Region.Physics.BulletXPlugin
rigidBody.ActivationState = ActivationState.DisableSimulation; rigidBody.ActivationState = ActivationState.DisableSimulation;
this._parent_scene.AddForgottenRigidBody(rigidBody); this._parent_scene.AddForgottenRigidBody(rigidBody);
} }
CreateRigidBody(this._parent_scene, this._position, size); CreateRigidBody(this._parent_scene, null, this._position, size); // Note, null for the meshing definitely is wrong. It's here for the moment to apease the compiler
if (_physical) Speed();//Static objects don't have linear velocity if (_physical) Speed();//Static objects don't have linear velocity
ReOrient(); ReOrient();
GC.Collect(); GC.Collect();

View File

@ -0,0 +1,161 @@
/*
Bullet for XNA Copyright (c) 2003-2007 Vsevolod Klementjev http://www.codeplex.com/xnadevru
Bullet original C++ version Copyright (c) 2003-2007 Erwin Coumans http://bulletphysics.com
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages
arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it
freely, subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not
claim that you wrote the original software. If you use this software
in a product, an acknowledgment in the product documentation would be
appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be
misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
*/
/*
This file contains a class TriangleIndexVertexArray. I tried using the class with the same name
from the BulletX implementation and found it unusable for the purpose of using triangle meshes
within BulletX as the implementation was painfully incomplete.
The attempt to derive from the original class failed as viable members were hidden.
Fiddling around with BulletX itself was not my intention.
So I copied the class to the BulletX-plugin and modified it.
If you want to fiddle around with it it's up to you to move all this to BulletX.
If someone someday implements the missing functionality in BulletX, feel free to remove this class.
It's just an ugly hack.
*/
using System;
using System.Collections.Generic;
using System.Text;
using MonoXnaCompactMaths;
namespace OpenSim.Region.Physics.BulletXPlugin
{
/// <summary>
/// IndexedMesh indexes into existing vertex and index arrays, in a similar way OpenGL glDrawElements
/// instead of the number of indices, we pass the number of triangles
/// </summary>
public struct IndexedMesh
{
private int _numTriangles;
private int[] _triangleIndexBase;
private int _triangleIndexStride;
private int _numVertices;
private Vector3[] _vertexBase;
private int _vertexStride;
public IndexedMesh(int numTriangleIndices, int[] triangleIndexBase, int triangleIndexStride, int numVertices, Vector3[] vertexBase, int vertexStride)
{
_numTriangles = numTriangleIndices;
_triangleIndexBase = triangleIndexBase;
_triangleIndexStride = triangleIndexStride;
_vertexBase = vertexBase;
_numVertices = numVertices;
_vertexStride = vertexStride;
}
public IndexedMesh(int[] triangleIndexBase, Vector3[] vertexBase)
{
_numTriangles = triangleIndexBase.Length;
_triangleIndexBase = triangleIndexBase;
_triangleIndexStride = 32;
_vertexBase = vertexBase;
_numVertices = vertexBase.Length;
_vertexStride = 24;
}
public int TriangleCount { get { return _numTriangles; } set { _numTriangles = value; } }
public int[] TriangleIndexBase { get { return _triangleIndexBase; } set { _triangleIndexBase = value; } }
public int TriangleIndexStride { get { return _triangleIndexStride; } set { _triangleIndexStride = value; } }
public int VertexCount { get { return _numVertices; } set { _numVertices = value; } }
public Vector3[] VertexBase { get { return _vertexBase; } set { _vertexBase = value; } }
public int VertexStride { get { return _vertexStride; } set { _vertexStride = value; } }
}
/// <summary>
/// TriangleIndexVertexArray allows to use multiple meshes, by indexing into existing triangle/index arrays.
/// Additional meshes can be added using addIndexedMesh
/// </summary>
public class TriangleIndexVertexArray : XnaDevRu.BulletX.StridingMeshInterface
{
List<IndexedMesh> _indexedMeshes = new List<IndexedMesh>();
public TriangleIndexVertexArray() { }
public TriangleIndexVertexArray(int numTriangleIndices, int[] triangleIndexBase, int triangleIndexStride, int numVertices, Vector3[] vertexBase, int vertexStride)
{
IndexedMesh mesh = new IndexedMesh();
mesh.TriangleCount = numTriangleIndices;
mesh.TriangleIndexBase = triangleIndexBase;
mesh.TriangleIndexStride = triangleIndexStride;
mesh.VertexBase = vertexBase;
mesh.VertexCount = numVertices;
mesh.VertexStride = vertexStride;
AddIndexedMesh(mesh);
}
public TriangleIndexVertexArray(int[] triangleIndexBase, Vector3[] vertexBase)
: this(triangleIndexBase.Length, triangleIndexBase, 32, vertexBase.Length, vertexBase, 24) { }
public void AddIndexedMesh(IndexedMesh indexedMesh)
{
_indexedMeshes.Add(indexedMesh);
}
public override void GetLockedVertexIndexBase(out List<Vector3> verts, out List<int> indicies, out int numfaces, int subpart)
{
throw new Exception("The method or operation is not implemented.");
}
public override void GetLockedReadOnlyVertexIndexBase(out List<Vector3> verts, out List<int> indicies, out int numfaces, int subpart)
{
IndexedMesh m = _indexedMeshes[0];
Vector3[] vertexBase = m.VertexBase;
verts = new List<Vector3>();
foreach (Vector3 v in vertexBase)
{
verts.Add(v);
}
int[] indexBase = m.TriangleIndexBase;
indicies = new List<int>();
foreach (int i in indexBase)
{
indicies.Add(i);
}
numfaces = vertexBase.GetLength(0);
}
public override void UnLockVertexBase(int subpart)
{
throw new Exception("The method or operation is not implemented.");
}
public override void UnLockReadOnlyVertexBase(int subpart)
{
}
public override int SubPartsCount()
{
return _indexedMeshes.Count;
}
public override void PreallocateVertices(int numverts)
{
throw new Exception("The method or operation is not implemented.");
}
public override void PreallocateIndices(int numindices)
{
throw new Exception("The method or operation is not implemented.");
}
}
}

View File

@ -0,0 +1,26 @@
using System;
using System.Collections.Generic;
using System.Text;
using OpenSim.Framework;
namespace OpenSim.Region.Physics.Manager
{
public interface IMesher
{
IMesh CreateMesh(String primName, PrimitiveBaseShape primShape, PhysicsVector size);
}
public interface IVertex {
}
public interface IMesh
{
List<PhysicsVector> getVertexList();
int[] getIndexListAsInt();
int[] getIndexListAsIntLocked();
float[] getVertexListAsFloatLocked();
}
}

View File

@ -30,6 +30,7 @@ using System.Collections.Generic;
using System.IO; using System.IO;
using System.Reflection; using System.Reflection;
using OpenSim.Framework.Console; using OpenSim.Framework.Console;
using Nini.Config;
namespace OpenSim.Region.Physics.Manager namespace OpenSim.Region.Physics.Manager
{ {
@ -38,28 +39,50 @@ namespace OpenSim.Region.Physics.Manager
/// </summary> /// </summary>
public class PhysicsPluginManager public class PhysicsPluginManager
{ {
private Dictionary<string, IPhysicsPlugin> _plugins = new Dictionary<string, IPhysicsPlugin>(); private Dictionary<string, IPhysicsPlugin> _PhysPlugins = new Dictionary<string, IPhysicsPlugin>();
private Dictionary<string, IMeshingPlugin> _MeshPlugins = new Dictionary<string, IMeshingPlugin>();
public PhysicsPluginManager() public PhysicsPluginManager()
{ {
} }
public PhysicsScene GetPhysicsScene(string engineName) public PhysicsScene GetPhysicsScene(string physEngineName, string meshEngineName)
{ {
if (String.IsNullOrEmpty(engineName))
if (String.IsNullOrEmpty(physEngineName))
{ {
return PhysicsScene.Null; return PhysicsScene.Null;
} }
if (_plugins.ContainsKey(engineName)) if (String.IsNullOrEmpty(meshEngineName))
{ {
MainLog.Instance.Verbose("PHYSICS", "creating " + engineName); return PhysicsScene.Null;
return _plugins[engineName].GetScene(); }
IMesher meshEngine = null;
if (_MeshPlugins.ContainsKey(meshEngineName))
{
MainLog.Instance.Verbose("PHYSICS", "creating meshing engine " + meshEngineName);
meshEngine = _MeshPlugins[meshEngineName].GetMesher();
} }
else else
{ {
MainLog.Instance.Warn("PHYSICS", "couldn't find physicsEngine: {0}", engineName); MainLog.Instance.Warn("PHYSICS", "couldn't find meshingEngine: {0}", meshEngineName);
throw new ArgumentException(String.Format("couldn't find physicsEngine: {0}", engineName)); throw new ArgumentException(String.Format("couldn't find meshingEngine: {0}", meshEngineName));
}
if (_PhysPlugins.ContainsKey(physEngineName))
{
MainLog.Instance.Verbose("PHYSICS", "creating " + physEngineName);
PhysicsScene result = _PhysPlugins[physEngineName].GetScene();
result.Initialise(meshEngine);
return result;
}
else
{
MainLog.Instance.Warn("PHYSICS", "couldn't find physicsEngine: {0}", physEngineName);
throw new ArgumentException(String.Format("couldn't find physicsEngine: {0}", physEngineName));
} }
} }
@ -85,18 +108,29 @@ namespace OpenSim.Region.Physics.Manager
{ {
if (!pluginType.IsAbstract) if (!pluginType.IsAbstract)
{ {
Type typeInterface = pluginType.GetInterface("IPhysicsPlugin", true); Type physTypeInterface = pluginType.GetInterface("IPhysicsPlugin", true);
if (typeInterface != null) if (physTypeInterface != null)
{ {
IPhysicsPlugin plug = IPhysicsPlugin plug =
(IPhysicsPlugin) Activator.CreateInstance(pluginAssembly.GetType(pluginType.ToString())); (IPhysicsPlugin) Activator.CreateInstance(pluginAssembly.GetType(pluginType.ToString()));
plug.Init(); plug.Init();
_plugins.Add(plug.GetName(), plug); _PhysPlugins.Add(plug.GetName(), plug);
MainLog.Instance.Verbose("PHYSICS", "Added physics engine: " + plug.GetName()); MainLog.Instance.Verbose("PHYSICS", "Added physics engine: " + plug.GetName());
} }
typeInterface = null; Type meshTypeInterface = pluginType.GetInterface("IMeshingPlugin", true);
if (meshTypeInterface != null)
{
IMeshingPlugin plug =
(IMeshingPlugin)Activator.CreateInstance(pluginAssembly.GetType(pluginType.ToString()));
_MeshPlugins.Add(plug.GetName(), plug);
MainLog.Instance.Verbose("PHYSICS", "Added meshing engine: " + plug.GetName());
}
physTypeInterface = null;
meshTypeInterface = null;
} }
} }
} }
@ -127,4 +161,11 @@ namespace OpenSim.Region.Physics.Manager
string GetName(); string GetName();
void Dispose(); void Dispose();
} }
}
public interface IMeshingPlugin
{
string GetName();
IMesher GetMesher();
}
}

View File

@ -28,6 +28,7 @@
using Axiom.Math; using Axiom.Math;
using OpenSim.Framework; using OpenSim.Framework;
using OpenSim.Framework.Console; using OpenSim.Framework.Console;
using OpenSim.Region.Physics.Manager;
namespace OpenSim.Region.Physics.Manager namespace OpenSim.Region.Physics.Manager
{ {
@ -38,6 +39,8 @@ namespace OpenSim.Region.Physics.Manager
get { return new NullPhysicsScene(); } get { return new NullPhysicsScene(); }
} }
public abstract void Initialise(IMesher meshmerizer);
public abstract PhysicsActor AddAvatar(string avName, PhysicsVector position); public abstract PhysicsActor AddAvatar(string avName, PhysicsVector position);
public abstract void RemoveAvatar(PhysicsActor actor); public abstract void RemoveAvatar(PhysicsActor actor);
@ -63,6 +66,12 @@ namespace OpenSim.Region.Physics.Manager
{ {
private static int m_workIndicator; private static int m_workIndicator;
public override void Initialise(IMesher meshmerizer)
{
// Does nothing right now
}
public override PhysicsActor AddAvatar(string avName, PhysicsVector position) public override PhysicsActor AddAvatar(string avName, PhysicsVector position)
{ {
MainLog.Instance.Verbose("NullPhysicsScene : AddAvatar({0})", position); MainLog.Instance.Verbose("NullPhysicsScene : AddAvatar({0})", position);
@ -123,4 +132,4 @@ namespace OpenSim.Region.Physics.Manager
} }
} }
} }
} }

View File

@ -0,0 +1,83 @@
using System;
using System.Collections.Generic;
using System.Text;
namespace OpenSim.Region.Physics.Meshing
{
class Extruder
{
public float startParameter;
public float stopParameter;
public Manager.PhysicsVector size;
public Mesh Extrude(Mesh m)
{
// Currently only works for iSteps=1;
Mesh result = new Mesh();
Mesh workingPlus = m.Clone();
Mesh workingMinus = m.Clone();
foreach (Vertex v in workingPlus.vertices)
{
if (v == null)
continue;
v.Z = +.5f;
v.X *= size.X;
v.Y *= size.Y;
v.Z *= size.Z;
}
foreach (Vertex v in workingMinus.vertices)
{
if (v == null)
continue;
v.Z = -.5f;
v.X *= size.X;
v.Y *= size.Y;
v.Z *= size.Z;
}
foreach (Triangle t in workingMinus.triangles)
{
t.invertNormal();
}
result.Append(workingMinus);
result.Append(workingPlus);
int iLastNull = 0;
for (int i = 0; i < workingPlus.vertices.Count; i++)
{
int iNext = (i + 1);
if (workingPlus.vertices[i] == null) // Can't make a simplex here
{
iLastNull = i+1;
continue;
}
if (i == workingPlus.vertices.Count-1) // End of list
{
iNext = iLastNull;
}
if (workingPlus.vertices[iNext] == null) // Null means wrap to begin of last segment
{
iNext = iLastNull;
}
Triangle tSide;
tSide = new Triangle(workingPlus.vertices[i], workingMinus.vertices[i], workingPlus.vertices[iNext]);
result.Add(tSide);
tSide = new Triangle(workingPlus.vertices[iNext], workingMinus.vertices[i], workingMinus.vertices[iNext]);
result.Add(tSide);
}
return result;
}
}
}

View File

@ -0,0 +1,306 @@
/*
* Copyright (c) Contributors, http://opensimulator.org/
* See CONTRIBUTORS.TXT for a full list of copyright holders.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* * Neither the name of the OpenSim Project nor the
* names of its contributors may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS AS IS AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
*/
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Globalization;
using OpenSim.Framework.Console;
using OpenSim.Region.Physics.Manager;
using OpenSim.Region.Physics.Meshing;
public class Vertex : PhysicsVector, IComparable<Vertex>
{
public Vertex(float x, float y, float z)
: base(x, y, z)
{
}
public Vertex(PhysicsVector v)
: base(v.X, v.Y, v.Z)
{
}
public Vertex Clone()
{
return new Vertex(X, Y, Z);
}
public static Vertex FromAngle(double angle)
{
return new Vertex((float)Math.Cos(angle), (float)Math.Sin(angle), 0.0f);
}
public virtual bool Equals(Vertex v, float tolerance)
{
PhysicsVector diff = this - v;
float d = diff.length();
if (d < tolerance)
return true;
return false;
}
public int CompareTo(Vertex other)
{
if (X < other.X)
return -1;
if (X > other.X)
return 1;
if (Y < other.Y)
return -1;
if (Y > other.Y)
return 1;
if (Z < other.Z)
return -1;
if (Z > other.Z)
return 1;
return 0;
}
public static bool operator >(Vertex me, Vertex other)
{
return me.CompareTo(other) > 0;
}
public static bool operator <(Vertex me, Vertex other)
{
return me.CompareTo(other) < 0;
}
public String ToRaw()
{
// Why this stuff with the number formatter?
// Well, the raw format uses the english/US notation of numbers
// where the "," separates groups of 1000 while the "." marks the border between 1 and 10E-1.
// The german notation uses these characters exactly vice versa!
// The Float.ToString() routine is a localized one, giving different results depending on the country
// settings your machine works with. Unusable for a machine readable file format :-(
NumberFormatInfo nfi = new NumberFormatInfo();
nfi.NumberDecimalSeparator = ".";
nfi.NumberDecimalDigits = 3;
String s1 = X.ToString("N2", nfi) + " " + Y.ToString("N2", nfi) + " " + Z.ToString("N2", nfi);
return s1;
}
}
public class Triangle
{
public Vertex v1;
public Vertex v2;
public Vertex v3;
private float radius_square;
private float cx;
private float cy;
public Triangle(Vertex _v1, Vertex _v2, Vertex _v3)
{
v1 = _v1;
v2 = _v2;
v3 = _v3;
CalcCircle();
}
public bool isInCircle(float x, float y)
{
float dx, dy;
float dd;
dx = x - cx;
dy = y - cy;
dd = dx*dx + dy*dy;
if (dd < radius_square)
return true;
else
return false;
}
public bool isDegraded()
{
// This means, the vertices of this triangle are somewhat strange.
// They either line up or at least two of them are identical
return (radius_square == 0.0);
}
private void CalcCircle()
{
// Calculate the center and the radius of a circle given by three points p1, p2, p3
// It is assumed, that the triangles vertices are already set correctly
double p1x, p2x, p1y, p2y, p3x, p3y;
// Deviation of this routine:
// A circle has the general equation (M-p)^2=r^2, where M and p are vectors
// this gives us three equations f(p)=r^2, each for one point p1, p2, p3
// putting respectively two equations together gives two equations
// f(p1)=f(p2) and f(p1)=f(p3)
// bringing all constant terms to one side brings them to the form
// M*v1=c1 resp.M*v2=c2 where v1=(p1-p2) and v2=(p1-p3) (still vectors)
// and c1, c2 are scalars (Naming conventions like the variables below)
// Now using the equations that are formed by the components of the vectors
// and isolate Mx lets you make one equation that only holds My
// The rest is straight forward and eaasy :-)
//
/* helping variables for temporary results */
double c1, c2;
double v1x, v1y, v2x, v2y;
double z, n;
double rx, ry;
// Readout the three points, the triangle consists of
p1x = v1.X;
p1y = v1.Y;
p2x = v2.X;
p2y = v2.Y;
p3x = v3.X;
p3y = v3.Y;
/* calc helping values first */
c1 = (p1x*p1x + p1y*p1y - p2x*p2x - p2y*p2y)/2;
c2 = (p1x*p1x + p1y*p1y - p3x*p3x - p3y*p3y)/2;
v1x = p1x - p2x;
v1y = p1y - p2y;
v2x = p1x - p3x;
v2y = p1y - p3y;
z = (c1*v2x - c2*v1x);
n = (v1y*v2x - v2y*v1x);
if (n == 0.0) // This is no triangle, i.e there are (at least) two points at the same location
{
radius_square = 0.0f;
return;
}
cy = (float) (z/n);
if (v2x != 0.0)
{
cx = (float) ((c2 - v2y*cy)/v2x);
}
else if (v1x != 0.0)
{
cx = (float) ((c1 - v1y*cy)/v1x);
}
else
{
Debug.Assert(false, "Malformed triangle"); /* Both terms zero means nothing good */
}
rx = (p1x - cx);
ry = (p1y - cy);
radius_square = (float) (rx*rx + ry*ry);
}
public List<Simplex> GetSimplices()
{
List<Simplex> result = new List<Simplex>();
Simplex s1 = new Simplex(v1, v2);
Simplex s2 = new Simplex(v2, v3);
Simplex s3 = new Simplex(v3, v1);
result.Add(s1);
result.Add(s2);
result.Add(s3);
return result;
}
public override String ToString()
{
NumberFormatInfo nfi = new NumberFormatInfo();
nfi.CurrencyDecimalDigits = 2;
nfi.CurrencyDecimalSeparator = ".";
String s1 = "<" + v1.X.ToString(nfi) + "," + v1.Y.ToString(nfi) + "," + v1.Z.ToString(nfi) + ">";
String s2 = "<" + v2.X.ToString(nfi) + "," + v2.Y.ToString(nfi) + "," + v2.Z.ToString(nfi) + ">";
String s3 = "<" + v3.X.ToString(nfi) + "," + v3.Y.ToString(nfi) + "," + v3.Z.ToString(nfi) + ">";
return s1 + ";" + s2 + ";" + s3;
}
public PhysicsVector getNormal()
{
// Vertices
// Vectors for edges
PhysicsVector e1;
PhysicsVector e2;
e1 = new PhysicsVector(v1.X - v2.X, v1.Y - v2.Y, v1.Z - v2.Z);
e2 = new PhysicsVector(v1.X - v3.X, v1.Y - v3.Y, v1.Z - v3.Z);
// Cross product for normal
PhysicsVector n = PhysicsVector.cross(e1, e2);
// Length
float l = n.length();
// Normalized "normal"
n = n / l;
return n;
}
public void invertNormal()
{
Vertex vt;
vt = v1;
v1 = v2;
v2 = vt;
}
// Dumps a triangle in the "raw faces" format, blender can import. This is for visualisation and
// debugging purposes
public String ToStringRaw()
{
String output = v1.ToRaw() + " " + v2.ToRaw() + " " +v3.ToRaw();
return output;
}
}

View File

@ -0,0 +1,213 @@
using System;
using System.IO;
using System.Collections.Generic;
using System.Text;
using System.Runtime.InteropServices;
using OpenSim.Region.Physics.Manager;
namespace OpenSim.Region.Physics.Meshing
{
public class Mesh : IMesh
{
public List<Vertex> vertices;
public List<Triangle> triangles;
public float[] normals;
public Mesh()
{
vertices = new List<Vertex>();
triangles = new List<Triangle>();
}
public Mesh Clone()
{
Mesh result = new Mesh();
foreach (Vertex v in vertices)
{
if (v == null)
result.vertices.Add(null);
else
result.vertices.Add(v.Clone());
}
foreach (Triangle t in triangles)
{
int iV1, iV2, iV3;
iV1 = this.vertices.IndexOf(t.v1);
iV2 = this.vertices.IndexOf(t.v2);
iV3 = this.vertices.IndexOf(t.v3);
Triangle newT = new Triangle(result.vertices[iV1], result.vertices[iV2], result.vertices[iV3]);
result.Add(newT);
}
return result;
}
public void Add(Triangle triangle)
{
int i;
i = vertices.IndexOf(triangle.v1);
if (i < 0)
throw new ArgumentException("Vertex v1 not known to mesh");
i = vertices.IndexOf(triangle.v2);
if (i < 0)
throw new ArgumentException("Vertex v2 not known to mesh");
i = vertices.IndexOf(triangle.v3);
if (i < 0)
throw new ArgumentException("Vertex v3 not known to mesh");
triangles.Add(triangle);
}
public void Add(Vertex v)
{
vertices.Add(v);
}
public void Remove(Vertex v)
{
int i;
// First, remove all triangles that are build on v
for (i = 0; i < triangles.Count; i++)
{
Triangle t = triangles[i];
if (t.v1 == v || t.v2 == v || t.v3 == v)
{
triangles.RemoveAt(i);
i--;
}
}
// Second remove v itself
vertices.Remove(v);
}
public void RemoveTrianglesOutside(SimpleHull hull)
{
int i;
for (i = 0; i < triangles.Count; i++)
{
Triangle t = triangles[i];
Vertex v1 = t.v1;
Vertex v2 = t.v2;
Vertex v3 = t.v3;
PhysicsVector m = v1 + v2 + v3;
m /= 3.0f;
if (!hull.IsPointIn(new Vertex(m)))
{
triangles.RemoveAt(i);
i--;
}
}
}
public void Add(List<Vertex> lv)
{
foreach (Vertex v in lv)
{
vertices.Add(v);
}
}
public List<PhysicsVector> getVertexList()
{
List<PhysicsVector> result = new List<PhysicsVector>();
foreach (Vertex v in vertices)
{
result.Add(v);
}
return result;
}
public float[] getVertexListAsFloatLocked()
{
float[] result = new float[vertices.Count * 3];
for (int i = 0; i < vertices.Count; i++)
{
Vertex v = vertices[i];
if (v == null)
continue;
result[3 * i + 0] = v.X;
result[3 * i + 1] = v.Y;
result[3 * i + 2] = v.Z;
}
GCHandle.Alloc(result, GCHandleType.Pinned);
return result;
}
public int[] getIndexListAsInt()
{
int[] result = new int[triangles.Count * 3];
for (int i = 0; i < triangles.Count; i++)
{
Triangle t = triangles[i];
result[3 * i + 0] = vertices.IndexOf(t.v1);
result[3 * i + 1] = vertices.IndexOf(t.v2);
result[3 * i + 2] = vertices.IndexOf(t.v3);
}
return result;
}
public int[] getIndexListAsIntLocked()
{
int[] result = getIndexListAsInt();
GCHandle.Alloc(result, GCHandleType.Pinned);
return result;
}
public void Append(Mesh newMesh)
{
foreach (Vertex v in newMesh.vertices)
vertices.Add(v);
foreach (Triangle t in newMesh.triangles)
Add(t);
}
// Do a linear transformation of mesh.
public void TransformLinear(float[,] matrix, float[] offset)
{
foreach (Vertex v in vertices)
{
if (v == null)
continue;
float x, y, z;
x = v.X * matrix[0, 0] + v.Y * matrix[1, 0] + v.Z * matrix[2, 0];
y = v.X * matrix[0, 1] + v.Y * matrix[1, 1] + v.Z * matrix[2, 1];
z = v.X * matrix[0, 2] + v.Y * matrix[1, 2] + v.Z * matrix[2, 2];
v.X = x + offset[0];
v.Y = y + offset[1];
v.Z = z + offset[2];
}
}
public void DumpRaw(String path, String name, String title)
{
if (path == null)
return;
String fileName = name + "_" + title + ".raw";
String completePath = Path.Combine(path, fileName);
StreamWriter sw = new StreamWriter(completePath);
foreach (Triangle t in triangles)
{
String s = t.ToStringRaw();
sw.WriteLine(s);
}
sw.Close();
}
}
}

View File

@ -0,0 +1,393 @@
/*
* Copyright (c) Contributors, http://opensimulator.org/
* See CONTRIBUTORS.TXT for a full list of copyright holders.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* * Neither the name of the OpenSim Project nor the
* names of its contributors may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS AS IS AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
*/
using System;
using System.IO;
using System.Globalization;
using System.Diagnostics;
using System.Collections.Generic;
using System.Runtime.InteropServices;
using OpenSim.Framework;
using OpenSim.Framework.Console;
using OpenSim.Region.Physics.Manager;
namespace OpenSim.Region.Physics.Meshing
{
public class MeshmerizerPlugin : IMeshingPlugin
{
public MeshmerizerPlugin()
{
}
public string GetName()
{
return "Meshmerizer";
}
public IMesher GetMesher()
{
return new Meshmerizer();
}
}
public class Meshmerizer : IMesher
{
// Setting baseDir to a path will enable the dumping of raw files
// raw files can be imported by blender so a visual inspection of the results can be done
// const string baseDir = "rawFiles";
const string baseDir = null;
static void IntersectionParameterPD(PhysicsVector p1, PhysicsVector r1, PhysicsVector p2, PhysicsVector r2, ref float lambda, ref float mu)
{
// p1, p2, points on the straight
// r1, r2, directional vectors of the straight. Not necessarily of length 1!
// note, that l, m can be scaled such, that the range 0..1 is mapped to the area between two points,
// thus allowing to decide whether an intersection is between two points
float r1x = r1.X;
float r1y = r1.Y;
float r2x = r2.X;
float r2y = r2.Y;
float denom = r1y*r2x - r1x*r2y;
if (denom == 0.0)
{
lambda = Single.NaN;
mu = Single.NaN;
return;
}
float p1x = p1.X;
float p1y = p1.Y;
float p2x = p2.X;
float p2y = p2.Y;
lambda = (-p2x * r2y + p1x * r2y + (p2y - p1y) * r2x) / denom;
mu = (-p2x * r1y + p1x * r1y + (p2y - p1y) * r1x) / denom;
}
private static List<Triangle> FindInfluencedTriangles(List<Triangle> triangles, Vertex v)
{
List<Triangle> influenced = new List<Triangle>();
foreach (Triangle t in triangles)
{
if (t.isInCircle(v.X, v.Y))
{
influenced.Add(t);
}
}
return influenced;
}
private static void InsertVertices(List<Vertex> vertices, int usedForSeed, List<Triangle> triangles)
{
// This is a variant of the delaunay algorithm
// each time a new vertex is inserted, all triangles that are influenced by it are deleted
// and replaced by new ones including the new vertex
// It is not very time efficient but easy to implement.
int iCurrentVertex;
int iMaxVertex = vertices.Count;
for (iCurrentVertex = usedForSeed; iCurrentVertex < iMaxVertex; iCurrentVertex++)
{
// Background: A triangle mesh fulfills the delaunay condition if (iff!)
// each circumlocutory circle (i.e. the circle that touches all three corners)
// of each triangle is empty of other vertices.
// Obviously a single (seeding) triangle fulfills this condition.
// If we now add one vertex, we need to reconstruct all triangles, that
// do not fulfill this condition with respect to the new triangle
// Find the triangles that are influenced by the new vertex
Vertex v=vertices[iCurrentVertex];
if (v == null)
continue; // Null is polygon stop marker. Ignore it
List<Triangle> influencedTriangles=FindInfluencedTriangles(triangles, v);
List<Simplex> simplices = new List<Simplex>();
// Reconstruction phase. First step, dissolve each triangle into it's simplices,
// i.e. it's "border lines"
// Goal is to find "inner" borders and delete them, while the hull gets conserved.
// Inner borders are special in the way that they always come twice, which is how we detect them
foreach (Triangle t in influencedTriangles)
{
List<Simplex> newSimplices = t.GetSimplices();
simplices.AddRange(newSimplices);
triangles.Remove(t);
}
// Now sort the simplices. That will make identical ones reside side by side in the list
simplices.Sort();
// Look for duplicate simplices here.
// Remember, they are directly side by side in the list right now,
// So we only check directly neighbours
int iSimplex;
List<Simplex> innerSimplices = new List<Simplex>();
for (iSimplex = 1; iSimplex < simplices.Count; iSimplex++) // Startindex=1, so we can refer backwards
{
if (simplices[iSimplex - 1].CompareTo(simplices[iSimplex]) == 0)
{
innerSimplices.Add(simplices[iSimplex - 1]);
innerSimplices.Add(simplices[iSimplex]);
}
}
foreach (Simplex s in innerSimplices)
{
simplices.Remove(s);
}
// each simplex still in the list belongs to the hull of the region in question
// The new vertex (yes, we still deal with verices here :-) ) forms a triangle
// with each of these simplices. Build the new triangles and add them to the list
foreach (Simplex s in simplices)
{
Triangle t = new Triangle(s.v1, s.v2, vertices[iCurrentVertex]);
if (!t.isDegraded())
{
triangles.Add(t);
}
}
}
}
static Mesh CreateBoxMesh(String primName, PrimitiveBaseShape primShape, PhysicsVector size)
// Builds the z (+ and -) surfaces of a box shaped prim
{
UInt16 hollowFactor = primShape.ProfileHollow;
UInt16 profileBegin = primShape.ProfileBegin;
UInt16 profileEnd = primShape.ProfileEnd;
// Procedure: This is based on the fact that the upper (plus) and lower (minus) Z-surface
// of a block are basically the same
// They may be warped differently but the shape is identical
// So we only create one surface as a model and derive both plus and minus surface of the block from it
// This is done in a model space where the block spans from -.5 to +.5 in X and Y
// The mapping to Scene space is done later during the "extrusion" phase
// Base
Vertex MM = new Vertex(-0.5f, -0.5f, 0.0f);
Vertex PM = new Vertex(+0.5f, -0.5f, 0.0f);
Vertex MP = new Vertex(-0.5f, +0.5f, 0.0f);
Vertex PP = new Vertex(+0.5f, +0.5f, 0.0f);
Meshing.SimpleHull outerHull = new SimpleHull();
outerHull.AddVertex(MM);
outerHull.AddVertex(PM);
outerHull.AddVertex(PP);
outerHull.AddVertex(MP);
// Deal with cuts now
if ((profileBegin != 0) || (profileEnd != 0))
{
double fProfileBeginAngle = profileBegin / 50000.0 * 360.0; // In degree, for easier debugging and understanding
fProfileBeginAngle -= (90.0 + 45.0); // for some reasons, the SL client counts from the corner -X/-Y
double fProfileEndAngle = 360.0 - profileEnd / 50000.0 * 360.0; // Pathend comes as complement to 1.0
fProfileEndAngle -= (90.0 + 45.0);
if (fProfileBeginAngle < fProfileEndAngle)
fProfileEndAngle -= 360.0;
// Note, that we don't want to cut out a triangle, even if this is a
// good approximation for small cuts. Indeed we want to cut out an arc
// and we approximate this arc by a polygon chain
// Also note, that these vectors are of length 1.0 and thus their endpoints lay outside the model space
// So it can easily be subtracted from the outer hull
int iSteps = (int)(((fProfileBeginAngle - fProfileEndAngle) / 45.0) + .5); // how many steps do we need with approximately 45 degree
double dStepWidth=(fProfileBeginAngle-fProfileEndAngle)/iSteps;
Vertex origin = new Vertex(0.0f, 0.0f, 0.0f);
// Note the sequence of vertices here. It's important to have the other rotational sense than in outerHull
SimpleHull cutHull = new SimpleHull();
cutHull.AddVertex(origin);
for (int i=0; i<iSteps; i++) {
double angle=fProfileBeginAngle-i*dStepWidth; // we count against the angle orientation!!!!
Vertex v = Vertex.FromAngle(angle * Math.PI / 180.0);
cutHull.AddVertex(v);
}
Vertex legEnd = Vertex.FromAngle(fProfileEndAngle * Math.PI / 180.0); // Calculated separately to avoid errors
cutHull.AddVertex(legEnd);
MainLog.Instance.Debug("Starting cutting of the hollow shape from the prim {1}", 0, primName);
SimpleHull cuttedHull = SimpleHull.SubtractHull(outerHull, cutHull);
outerHull = cuttedHull;
}
// Deal with the hole here
if (hollowFactor > 0)
{
float hollowFactorF = (float) hollowFactor/(float) 50000;
Vertex IMM = new Vertex(-0.5f * hollowFactorF, -0.5f * hollowFactorF, 0.0f);
Vertex IPM = new Vertex(+0.5f * hollowFactorF, -0.5f * hollowFactorF, 0.0f);
Vertex IMP = new Vertex(-0.5f * hollowFactorF, +0.5f * hollowFactorF, 0.0f);
Vertex IPP = new Vertex(+0.5f * hollowFactorF, +0.5f * hollowFactorF, 0.0f);
SimpleHull holeHull = new SimpleHull();
holeHull.AddVertex(IMM);
holeHull.AddVertex(IMP);
holeHull.AddVertex(IPP);
holeHull.AddVertex(IPM);
SimpleHull hollowedHull = SimpleHull.SubtractHull(outerHull, holeHull);
outerHull = hollowedHull;
}
Mesh m = new Mesh();
Vertex Seed1 = new Vertex(0.0f, -10.0f, 0.0f);
Vertex Seed2 = new Vertex(-10.0f, 10.0f, 0.0f);
Vertex Seed3 = new Vertex(10.0f, 10.0f, 0.0f);
m.Add(Seed1);
m.Add(Seed2);
m.Add(Seed3);
m.Add(new Triangle(Seed1, Seed2, Seed3));
m.Add(outerHull.getVertices());
InsertVertices(m.vertices, 3, m.triangles);
m.DumpRaw(baseDir, primName, "Proto first Mesh");
m.Remove(Seed1);
m.Remove(Seed2);
m.Remove(Seed3);
m.DumpRaw(baseDir, primName, "Proto seeds removed");
m.RemoveTrianglesOutside(outerHull);
m.DumpRaw(baseDir, primName, "Proto outsides removed");
foreach (Triangle t in m.triangles)
{
PhysicsVector n = t.getNormal();
if (n.Z < 0.0)
t.invertNormal();
}
Extruder extr = new Extruder();
extr.size = size;
Mesh result = extr.Extrude(m);
result.DumpRaw(baseDir, primName, "Z extruded");
return result;
}
public static void CalcNormals(Mesh mesh)
{
int iTriangles = mesh.triangles.Count;
mesh.normals = new float[iTriangles*3];
int i = 0;
foreach (Triangle t in mesh.triangles)
{
float ux, uy, uz;
float vx, vy, vz;
float wx, wy, wz;
ux = t.v1.X;
uy = t.v1.Y;
uz = t.v1.Z;
vx = t.v2.X;
vy = t.v2.Y;
vz = t.v2.Z;
wx = t.v3.X;
wy = t.v3.Y;
wz = t.v3.Z;
// Vectors for edges
float e1x, e1y, e1z;
float e2x, e2y, e2z;
e1x = ux - vx;
e1y = uy - vy;
e1z = uz - vz;
e2x = ux - wx;
e2y = uy - wy;
e2z = uz - wz;
// Cross product for normal
float nx, ny, nz;
nx = e1y*e2z - e1z*e2y;
ny = e1z*e2x - e1x*e2z;
nz = e1x*e2y - e1y*e2x;
// Length
float l = (float) Math.Sqrt(nx*nx + ny*ny + nz*nz);
// Normalized "normal"
nx /= l;
ny /= l;
nz /= l;
mesh.normals[i] = nx;
mesh.normals[i + 1] = ny;
mesh.normals[i + 2] = nz;
i += 3;
}
}
public IMesh CreateMesh(String primName, PrimitiveBaseShape primShape, PhysicsVector size)
{
Mesh mesh = null;
switch (primShape.ProfileShape)
{
case ProfileShape.Square:
mesh=CreateBoxMesh(primName, primShape, size);
CalcNormals(mesh);
break;
default:
mesh = CreateBoxMesh(primName, primShape, size);
CalcNormals(mesh);
//Set default mesh to cube otherwise it'll return
// null and crash on the 'setMesh' method in the physics plugins.
//mesh = null;
break;
}
return mesh;
}
}
}

View File

@ -0,0 +1,363 @@
using System;
using System.Collections.Generic;
using System.Text;
using OpenSim.Framework.Console;
namespace OpenSim.Region.Physics.Meshing
{
// A simple hull is a set of vertices building up to simplices that border a region
// The word simple referes to the fact, that this class assumes, that all simplices
// do not intersect
// Simple hulls can be added and subtracted.
// Vertices can be checked to lie inside a hull
// Also note, that the sequence of the vertices is important and defines if the region that
// is defined by the hull lies inside or outside the simplex chain
public class SimpleHull
{
List<Vertex> vertices = new List<Vertex>();
List<Vertex> holeVertices = new List<Vertex>(); // Only used, when the hull is hollow
// Adds a vertex to the end of the list
public void AddVertex(Vertex v) {
vertices.Add(v);
}
override public String ToString()
{
String result="";
foreach (Vertex v in vertices)
{
result += "b:" + v.ToString() + "\n";
}
return result;
}
public List<Vertex> getVertices() {
List<Vertex> newVertices = new List<Vertex>();
newVertices.AddRange(vertices);
newVertices.Add(null);
newVertices.AddRange(holeVertices);
return newVertices;
}
public SimpleHull Clone()
{
SimpleHull result = new SimpleHull();
foreach (Vertex v in vertices)
{
result.AddVertex(v.Clone());
}
foreach (Vertex v in this.holeVertices)
{
result.holeVertices.Add(v.Clone());
}
return result;
}
public bool IsPointIn(Vertex v1)
{
int iCounter=0;
List<Simplex> simplices=buildSimplexList();
foreach (Simplex s in simplices)
{
// Send a ray along the positive X-Direction
// Note, that this direction must correlate with the "below" interpretation
// of handling for the special cases below
Manager.PhysicsVector intersection = s.RayIntersect(v1, new Manager.PhysicsVector(1.0f, 0.0f, 0.0f), true);
if (intersection == null)
continue; // No intersection. Done. More tests to follow otherwise
// Did we hit the end of a simplex?
// Then this can be one of two special cases:
// 1. we go through a border exactly at a joint
// 2. we have just marginally touched a corner
// 3. we can slide along a border
// Solution: If the other vertex is "below" the ray, we don't count it
// Thus corners pointing down are counted twice, corners pointing up are not counted
// borders are counted once
if (intersection.IsIdentical(s.v1, 0.001f)) {
if (s.v2.Y < v1.Y)
continue;
}
// Do this for the other vertex two
if (intersection.IsIdentical(s.v2, 0.001f)) {
if (s.v1.Y<v1.Y)
continue;
}
iCounter++;
}
return iCounter % 2 == 1; // Point is inside if the number of intersections is odd
}
public bool containsPointsFrom(SimpleHull otherHull)
{
foreach (Vertex v in otherHull.vertices)
{
if (IsPointIn(v))
return true;
}
return false;
}
List<Simplex> buildSimplexList() {
List<Simplex> result = new List<Simplex>();
// Not asserted but assumed: at least three vertices
for (int i=0; i<vertices.Count-1; i++) {
Simplex s=new Simplex(vertices[i], vertices[i+1]);
result.Add(s);
}
Simplex s1=new Simplex(vertices[vertices.Count-1], vertices[0]);
result.Add(s1);
if (holeVertices.Count==0)
return result;
// Same here. At least three vertices in hole assumed
for (int i = 0; i < holeVertices.Count - 1; i++)
{
Simplex s = new Simplex(holeVertices[i], holeVertices[i + 1]);
result.Add(s);
}
s1 = new Simplex(holeVertices[holeVertices.Count - 1], holeVertices[0]);
result.Add(s1);
return result;
}
bool InsertVertex(Vertex v, int iAfter)
{
vertices.Insert(iAfter + 1, v);
return true;
}
Vertex getNextVertex(Vertex currentVertex)
{
int iCurrentIndex;
iCurrentIndex = vertices.IndexOf(currentVertex);
// Error handling for iCurrentIndex==-1 should go here (and probably never will)
iCurrentIndex++;
if (iCurrentIndex == vertices.Count)
iCurrentIndex = 0;
return vertices[iCurrentIndex];
}
public Vertex FindVertex(Vertex vBase, float tolerance) {
foreach (Vertex v in vertices) {
if (v.IsIdentical(vBase, tolerance))
return v;
}
return null;
}
public void FindIntersection(Simplex s, ref Vertex Intersection, ref Vertex nextVertex)
{
Vertex bestIntersection=null;
float distToV1=Single.PositiveInfinity;
Simplex bestIntersectingSimplex=null;
List<Simplex> simple = buildSimplexList();
foreach (Simplex sTest in simple)
{
Manager.PhysicsVector vvTemp = Simplex.Intersect(sTest, s, -.001f, -.001f, 0.999f, .999f);
Vertex vTemp=null;
if (vvTemp != null)
vTemp = new Vertex(vvTemp);
if (vTemp!=null) {
Manager.PhysicsVector diff=(s.v1-vTemp);
float distTemp=diff.length();
if (bestIntersection==null || distTemp<distToV1) {
bestIntersection=vTemp;
distToV1=distTemp;
bestIntersectingSimplex = sTest;
}
} // end if vTemp
} // end foreach
Intersection = bestIntersection;
if (bestIntersectingSimplex != null)
nextVertex = bestIntersectingSimplex.v2;
else
nextVertex = null;
}
public static SimpleHull SubtractHull(SimpleHull baseHull, SimpleHull otherHull)
{
SimpleHull baseHullClone = baseHull.Clone();
SimpleHull otherHullClone = otherHull.Clone();
bool intersects = false;
MainLog.Instance.Debug("State before intersection detection");
MainLog.Instance.Debug("The baseHull is:\n{1}", 0, baseHullClone.ToString());
MainLog.Instance.Debug("The otherHull is:\n{1}", 0, otherHullClone.ToString());
{
int iBase, iOther;
// Insert into baseHull
for (iBase = 0; iBase < baseHullClone.vertices.Count; iBase++)
{
int iBaseNext = (iBase + 1) % baseHullClone.vertices.Count;
Simplex sBase = new Simplex(baseHullClone.vertices[iBase], baseHullClone.vertices[iBaseNext]);
for (iOther = 0; iOther < otherHullClone.vertices.Count; iOther++)
{
int iOtherNext = (iOther + 1) % otherHullClone.vertices.Count;
Simplex sOther = new Simplex(otherHullClone.vertices[iOther], otherHullClone.vertices[iOtherNext]);
Manager.PhysicsVector intersect = Simplex.Intersect(sBase, sOther, 0.001f, -.001f, 0.999f, 1.001f);
if (intersect != null)
{
Vertex vIntersect = new Vertex(intersect);
baseHullClone.vertices.Insert(iBase + 1, vIntersect);
sBase.v2 = vIntersect;
intersects = true;
}
}
}
}
MainLog.Instance.Debug("State after intersection detection for the base hull");
MainLog.Instance.Debug("The baseHull is:\n{1}", 0, baseHullClone.ToString());
{
int iOther, iBase;
// Insert into otherHull
for (iOther = 0; iOther < otherHullClone.vertices.Count; iOther++)
{
int iOtherNext = (iOther + 1) % otherHullClone.vertices.Count;
Simplex sOther = new Simplex(otherHullClone.vertices[iOther], otherHullClone.vertices[iOtherNext]);
for (iBase = 0; iBase < baseHullClone.vertices.Count; iBase++)
{
int iBaseNext = (iBase + 1) % baseHullClone.vertices.Count;
Simplex sBase = new Simplex(baseHullClone.vertices[iBase], baseHullClone.vertices[iBaseNext]);
Manager.PhysicsVector intersect = Simplex.Intersect(sBase, sOther, -.001f, 0.001f, 1.001f, 0.999f);
if (intersect != null)
{
Vertex vIntersect = new Vertex(intersect);
otherHullClone.vertices.Insert(iOther + 1, vIntersect);
sOther.v2 = vIntersect;
intersects = true;
}
}
}
}
MainLog.Instance.Debug("State after intersection detection for the base hull");
MainLog.Instance.Debug("The otherHull is:\n{1}", 0, otherHullClone.ToString());
bool otherIsInBase = baseHullClone.containsPointsFrom(otherHullClone);
if (!intersects && otherIsInBase)
{
// We have a hole here
baseHullClone.holeVertices = otherHullClone.vertices;
return baseHullClone;
}
SimpleHull result = new SimpleHull();
// Find a good starting Simplex from baseHull
// A good starting simplex is one that is outside otherHull
// Such a simplex must exist, otherwise the result will be empty
Vertex baseStartVertex = null;
{
int iBase;
for (iBase = 0; iBase < baseHullClone.vertices.Count; iBase++)
{
int iBaseNext = (iBase + 1) % baseHullClone.vertices.Count;
Vertex center = new Vertex((baseHullClone.vertices[iBase] + baseHullClone.vertices[iBaseNext]) / 2.0f);
bool isOutside = !otherHullClone.IsPointIn(center);
if (isOutside)
{
baseStartVertex = baseHullClone.vertices[iBaseNext];
break;
}
}
}
if (baseStartVertex == null) // i.e. no simplex fulfilled the "outside" condition.
// In otherwords, subtractHull completely embraces baseHull
{
return result;
}
// The simplex that *starts* with baseStartVertex is outside the cutting hull,
// so we can start our walk with the next vertex without loosing a branch
Vertex V1 = baseStartVertex;
bool onBase = true;
// And here is how we do the magic :-)
// Start on the base hull.
// Walk the vertices in the positive direction
// For each vertex check, whether it is a vertex shared with the other hull
// if this is the case, switch over to walking the other vertex list.
// Note: The other hull *must* go backwards to our starting point (via several orther vertices)
// Thus it is important that the cutting hull has the inverse directional sense than the
// base hull!!!!!!!!! (means if base goes CW around it's center cutting hull must go CCW)
bool done = false;
while (!done)
{
result.AddVertex(V1);
Vertex nextVertex = null;
if (onBase)
{
nextVertex = otherHullClone.FindVertex(V1, 0.001f);
}
else
{
nextVertex = baseHullClone.FindVertex(V1, 0.001f);
}
if (nextVertex != null) // A node that represents an intersection
{
V1 = nextVertex; // Needed to find the next vertex on the other hull
onBase = !onBase;
}
if (onBase)
V1 = baseHullClone.getNextVertex(V1);
else
V1 = otherHullClone.getNextVertex(V1);
if (V1 == baseStartVertex)
done = true;
}
MainLog.Instance.Debug("The resulting Hull is:\n{1}", 0, result.ToString());
return result;
}
}
}

View File

@ -0,0 +1,198 @@
using System;
using System.Collections.Generic;
using System.Text;
using OpenSim.Region.Physics.Manager;
namespace OpenSim.Region.Physics.Meshing
{
// A simplex is a section of a straight line.
// It is defined by its endpoints, i.e. by two vertices
// Operation on vertices are
public class Simplex : IComparable<Simplex>
{
public Vertex v1;
public Vertex v2;
public Simplex(Vertex _v1, Vertex _v2)
{
v1 = _v1;
v2 = _v2;
}
public int CompareTo(Simplex other)
{
Vertex lv1, lv2, ov1, ov2, temp;
lv1 = v1;
lv2 = v2;
ov1 = other.v1;
ov2 = other.v2;
if (lv1 > lv2)
{
temp = lv1;
lv1 = lv2;
lv2 = temp;
}
if (ov1 > ov2)
{
temp = ov1;
ov1 = ov2;
ov2 = temp;
}
if (lv1 > ov1)
{
return 1;
}
if (lv1 < ov1)
{
return -1;
}
if (lv2 > ov2)
{
return 1;
}
if (lv2 < ov2)
{
return -1;
}
return 0;
}
private static void intersectParameter(PhysicsVector p1, PhysicsVector r1, PhysicsVector p2, PhysicsVector r2, ref float lambda, ref float mu)
{
// Intersects two straights
// p1, p2, points on the straight
// r1, r2, directional vectors of the straight. Not necessarily of length 1!
// note, that l, m can be scaled such, that the range 0..1 is mapped to the area between two points,
// thus allowing to decide whether an intersection is between two points
float r1x = r1.X;
float r1y = r1.Y;
float r2x = r2.X;
float r2y = r2.Y;
float denom = r1y*r2x - r1x*r2y;
float p1x = p1.X;
float p1y = p1.Y;
float p2x = p2.X;
float p2y = p2.Y;
float z1=-p2x * r2y + p1x * r2y + (p2y - p1y) * r2x;
float z2=-p2x * r1y + p1x * r1y + (p2y - p1y) * r1x;
if (denom == 0.0f) // Means the straights are parallel. Either no intersection or an infinite number of them
{
if (z1==0.0f) {// Means they are identical -> many, many intersections
lambda = Single.NaN;
mu = Single.NaN;
} else {
lambda = Single.PositiveInfinity;
mu = Single.PositiveInfinity;
}
return;
}
lambda = z1 / denom;
mu = z2 / denom;
}
// Intersects the simplex with another one.
// the borders are used to deal with float inaccuracies
// As a rule of thumb, the borders are
// lowerBorder1 : 0.0
// lowerBorder2 : 0.0
// upperBorder1 : 1.0
// upperBorder2 : 1.0
// Set these to values near the given parameters (e.g. 0.001 instead of 1 to exclude simplex starts safely, or to -0.001 to include them safely)
public static PhysicsVector Intersect(
Simplex s1,
Simplex s2,
float lowerBorder1,
float lowerBorder2,
float upperBorder1,
float upperBorder2)
{
PhysicsVector firstSimplexDirection = s1.v2 - s1.v1;
PhysicsVector secondSimplexDirection = s2.v2 - s2.v1;
float lambda = 0.0f;
float mu = 0.0f;
// Give us the parameters of an intersection. This subroutine does *not* take the constraints
// (intersection must be between v1 and v2 and it must be in the positive direction of the ray)
// into account. We do that afterwards.
intersectParameter(s1.v1, firstSimplexDirection, s2.v1, secondSimplexDirection, ref lambda, ref mu);
if (Single.IsInfinity(lambda)) // Special case. No intersection at all. directions parallel.
return null;
if (Single.IsNaN(lambda)) // Special case. many, many intersections.
return null;
if (lambda > upperBorder1) // We're behind v2
return null;
if (lambda < lowerBorder1)
return null;
if (mu < lowerBorder2) // outside simplex 2
return null;
if (mu > upperBorder2) // outside simplex 2
return null;
return s1.v1 + lambda * firstSimplexDirection;
}
// Intersects the simplex with a ray. The ray is defined as all p=origin + lambda*direction
// where lambda >= 0
public PhysicsVector RayIntersect(Vertex origin, PhysicsVector direction, bool bEndsIncluded)
{
PhysicsVector simplexDirection = v2 - v1;
float lambda = 0.0f;
float mu = 0.0f;
// Give us the parameters of an intersection. This subroutine does *not* take the constraints
// (intersection must be between v1 and v2 and it must be in the positive direction of the ray)
// into account. We do that afterwards.
intersectParameter(v1, simplexDirection, origin, direction, ref lambda, ref mu);
if (Single.IsInfinity(lambda)) // Special case. No intersection at all. directions parallel.
return null;
if (Single.IsNaN(lambda)) // Special case. many, many intersections.
return null;
if (mu < 0.0) // We're on the wrong side of the ray
return null;
if (lambda > 1.0) // We're behind v2
return null;
if (lambda == 1.0 && !bEndsIncluded)
return null; // The end of the simplices are not included
if (lambda < 0.0f) // we're before v1;
return null;
return this.v1 + lambda * simplexDirection;
}
}
}

View File

@ -32,7 +32,7 @@ using Axiom.Math;
using Ode.NET; using Ode.NET;
using OpenSim.Framework; using OpenSim.Framework;
using OpenSim.Region.Physics.Manager; using OpenSim.Region.Physics.Manager;
using OpenSim.Region.Physics.OdePlugin.Meshing; //using OpenSim.Region.Physics.OdePlugin.Meshing;
namespace OpenSim.Region.Physics.OdePlugin namespace OpenSim.Region.Physics.OdePlugin
{ {
@ -98,6 +98,8 @@ namespace OpenSim.Region.Physics.OdePlugin
public IntPtr space; public IntPtr space;
public static Object OdeLock = new Object(); public static Object OdeLock = new Object();
public IMesher mesher;
public OdeScene() public OdeScene()
{ {
nearCallback = near; nearCallback = near;
@ -137,6 +139,12 @@ namespace OpenSim.Region.Physics.OdePlugin
} }
public override void Initialise(IMesher meshmerizer)
{
mesher = meshmerizer;
}
// This function blatantly ripped off from BoxStack.cs // This function blatantly ripped off from BoxStack.cs
private void near(IntPtr space, IntPtr g1, IntPtr g2) private void near(IntPtr space, IntPtr g1, IntPtr g2)
{ {
@ -308,7 +316,7 @@ namespace OpenSim.Region.Physics.OdePlugin
} }
private PhysicsActor AddPrim(String name, PhysicsVector position, PhysicsVector size, Quaternion rotation, private PhysicsActor AddPrim(String name, PhysicsVector position, PhysicsVector size, Quaternion rotation,
Mesh mesh, PrimitiveBaseShape pbs, bool isphysical) IMesh mesh, PrimitiveBaseShape pbs, bool isphysical)
{ {
PhysicsVector pos = new PhysicsVector(); PhysicsVector pos = new PhysicsVector();
pos.X = position.X; pos.X = position.X;
@ -409,11 +417,12 @@ namespace OpenSim.Region.Physics.OdePlugin
{ {
return this.AddPrimShape(primName, pbs, position, size, rotation, false); return this.AddPrimShape(primName, pbs, position, size, rotation, false);
} }
public override PhysicsActor AddPrimShape(string primName, PrimitiveBaseShape pbs, PhysicsVector position, public override PhysicsActor AddPrimShape(string primName, PrimitiveBaseShape pbs, PhysicsVector position,
PhysicsVector size, Quaternion rotation, bool isPhysical) PhysicsVector size, Quaternion rotation, bool isPhysical)
{ {
PhysicsActor result; PhysicsActor result;
Mesh mesh = null; IMesh mesh = null;
switch (pbs.ProfileShape) switch (pbs.ProfileShape)
{ {
@ -421,7 +430,7 @@ namespace OpenSim.Region.Physics.OdePlugin
/// support simple box & hollow box now; later, more shapes /// support simple box & hollow box now; later, more shapes
if (needsMeshing(pbs)) if (needsMeshing(pbs))
{ {
mesh = Meshmerizer.CreateMesh(primName, pbs, size); mesh = mesher.CreateMesh(primName, pbs, size);
} }
break; break;
@ -931,7 +940,7 @@ namespace OpenSim.Region.Physics.OdePlugin
private PhysicsVector _acceleration; private PhysicsVector _acceleration;
public Quaternion _orientation; public Quaternion _orientation;
private Mesh _mesh; private IMesh _mesh;
private PrimitiveBaseShape _pbs; private PrimitiveBaseShape _pbs;
private OdeScene _parent_scene; private OdeScene _parent_scene;
public IntPtr prim_geom; public IntPtr prim_geom;
@ -953,7 +962,7 @@ namespace OpenSim.Region.Physics.OdePlugin
public OdePrim(String primName, OdeScene parent_scene, PhysicsVector pos, PhysicsVector size, public OdePrim(String primName, OdeScene parent_scene, PhysicsVector pos, PhysicsVector size,
Quaternion rotation, Mesh mesh, PrimitiveBaseShape pbs, bool pisPhysical) Quaternion rotation, IMesh mesh, PrimitiveBaseShape pbs, bool pisPhysical)
{ {
@ -1036,15 +1045,15 @@ namespace OpenSim.Region.Physics.OdePlugin
Body = (IntPtr)0; Body = (IntPtr)0;
} }
} }
public void setMesh(OdeScene parent_scene, Mesh mesh) public void setMesh(OdeScene parent_scene, IMesh mesh)
{ {
//Kill Body so that mesh can re-make the geom //Kill Body so that mesh can re-make the geom
if (IsPhysical && Body != (IntPtr)0) if (IsPhysical && Body != (IntPtr)0)
{ {
disableBody(); disableBody();
} }
float[] vertexList = mesh.getVertexListAsFloat(); // Note, that vertextList is pinned in memory float[] vertexList = mesh.getVertexListAsFloatLocked(); // Note, that vertextList is pinned in memory
int[] indexList = mesh.getIndexListAsInt(); // Also pinned, needs release after usage int[] indexList = mesh.getIndexListAsIntLocked(); // Also pinned, needs release after usage
int VertexCount = vertexList.GetLength(0)/3; int VertexCount = vertexList.GetLength(0)/3;
int IndexCount = indexList.GetLength(0); int IndexCount = indexList.GetLength(0);
@ -1169,7 +1178,7 @@ namespace OpenSim.Region.Physics.OdePlugin
// Don't need to re-enable body.. it's done in SetMesh // Don't need to re-enable body.. it's done in SetMesh
Mesh mesh = Meshmerizer.CreateMesh(oldname, _pbs, _size); IMesh mesh = _parent_scene.mesher.CreateMesh(oldname, _pbs, _size);
// createmesh returns null when it's a shape that isn't a cube. // createmesh returns null when it's a shape that isn't a cube.
if (mesh != null) if (mesh != null)
setMesh(_parent_scene, mesh); setMesh(_parent_scene, mesh);
@ -1218,7 +1227,7 @@ namespace OpenSim.Region.Physics.OdePlugin
// Construction of new prim // Construction of new prim
if (this._parent_scene.needsMeshing(_pbs)) if (this._parent_scene.needsMeshing(_pbs))
{ {
Mesh mesh = Meshmerizer.CreateMesh(oldname, _pbs, _size); IMesh mesh = _parent_scene.mesher.CreateMesh(oldname, _pbs, _size);
setMesh(_parent_scene, mesh); setMesh(_parent_scene, mesh);
} else { } else {
prim_geom = d.CreateBox(_parent_scene.space, _size.X, _size.Y, _size.Z); prim_geom = d.CreateBox(_parent_scene.space, _size.X, _size.Y, _size.Z);

View File

@ -84,6 +84,12 @@ namespace OpenSim.Region.Physics.PhysXPlugin
scene = mySdk.CreateScene(); scene = mySdk.CreateScene();
} }
public override void Initialise(IMesher meshmerizer)
{
// Does nothing right now
}
public override PhysicsActor AddAvatar(string avName, PhysicsVector position) public override PhysicsActor AddAvatar(string avName, PhysicsVector position)
{ {
Vec3 pos = new Vec3(); Vec3 pos = new Vec3();

View File

@ -251,7 +251,8 @@
<Reference name="Axiom.MathLib.dll" localCopy="false"/> <Reference name="Axiom.MathLib.dll" localCopy="false"/>
<Reference name="OpenSim.Framework" localCopy="false"/> <Reference name="OpenSim.Framework" localCopy="false"/>
<Reference name="OpenSim.Framework.Console" localCopy="false"/> <Reference name="OpenSim.Framework.Console" localCopy="false"/>
<Files> <Reference name="Nini.dll" />
<Files>
<Match pattern="*.cs" recurse="false"/> <Match pattern="*.cs" recurse="false"/>
</Files> </Files>
</Project> </Project>
@ -346,8 +347,9 @@
<Reference name="System" localCopy="false"/> <Reference name="System" localCopy="false"/>
<Reference name="libsecondlife.dll"/> <Reference name="libsecondlife.dll"/>
<Reference name="Axiom.MathLib.dll" localCopy="false"/> <Reference name="Axiom.MathLib.dll" localCopy="false"/>
<Reference name="OpenSim.Framework"/> <Reference name="OpenSim.Framework"/>
<Reference name="OpenSim.Region.Physics.Manager" localCopy="false"/> <Reference name="OpenSim.Framework.Console" localCopy="false"/>
<Reference name="OpenSim.Region.Physics.Manager" localCopy="false"/>
<Reference name="Modified.XnaDevRu.BulletX.dll" localCopy="false" /> <Reference name="Modified.XnaDevRu.BulletX.dll" localCopy="false" />
<Reference name="MonoXnaCompactMaths.dll" localCopy="false" /> <Reference name="MonoXnaCompactMaths.dll" localCopy="false" />
@ -356,6 +358,30 @@
</Files> </Files>
</Project> </Project>
<Project name="OpenSim.Region.Physics.Meshing" path="OpenSim/Region/Physics/Meshing" 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" localCopy="false"/>
<Reference name="libsecondlife.dll"/>
<Reference name="OpenSim.Framework"/>
<Reference name="OpenSim.Framework.Console"/>
<Reference name="OpenSim.Region.Physics.Manager" localCopy="false"/>
<Files>
<Match pattern="*.cs" recurse="true"/>
</Files>
</Project>
<!-- Terrain engine --> <!-- Terrain engine -->
<Project name="OpenSim.Region.Terrain.BasicTerrain" path="OpenSim/Region/Terrain.BasicTerrain" type="Library"> <Project name="OpenSim.Region.Terrain.BasicTerrain" path="OpenSim/Region/Terrain.BasicTerrain" type="Library">
@ -564,8 +590,10 @@
<Reference name="OpenSim.Region.Communications.Local"/> <Reference name="OpenSim.Region.Communications.Local"/>
<Reference name="OpenSim.Region.Physics.Manager"/> <Reference name="OpenSim.Region.Physics.Manager"/>
<Reference name="XMLRPC.dll"/> <Reference name="XMLRPC.dll"/>
<Reference name="Nini.dll" />
<Files>
<Files>
<Match pattern="*.cs" recurse="true"/> <Match pattern="*.cs" recurse="true"/>
</Files> </Files>
</Project> </Project>
@ -1108,3 +1136,4 @@