rename Ubitode
parent
774c42e7fb
commit
d2d34a473d
|
@ -1,340 +0,0 @@
|
||||||
/*
|
|
||||||
* Copyright (c) Contributors, http://opensimulator.org/
|
|
||||||
* See CONTRIBUTORS.TXT for a full list of copyright holders.
|
|
||||||
*
|
|
||||||
* Redistribution and use in source and binary forms, with or without
|
|
||||||
* modification, are permitted provided that the following conditions are met:
|
|
||||||
* * Redistributions of source code must retain the above copyright
|
|
||||||
* notice, this list of conditions and the following disclaimer.
|
|
||||||
* * Redistributions in binary form must reproduce the above copyright
|
|
||||||
* notice, this list of conditions and the following disclaimer in the
|
|
||||||
* documentation and/or other materials provided with the distribution.
|
|
||||||
* * Neither the name of the OpenSimulator Project nor the
|
|
||||||
* names of its contributors may be used to endorse or promote products
|
|
||||||
* derived from this software without specific prior written permission.
|
|
||||||
*
|
|
||||||
* THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
|
|
||||||
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
|
||||||
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
|
||||||
* DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
|
|
||||||
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
|
||||||
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
|
||||||
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
|
||||||
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
|
||||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
|
||||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
||||||
*/
|
|
||||||
|
|
||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Diagnostics;
|
|
||||||
using System.Globalization;
|
|
||||||
using OpenMetaverse;
|
|
||||||
using OpenSim.Region.PhysicsModules.SharedBase;
|
|
||||||
using OpenSim.Region.PhysicsModules.UbitMeshing;
|
|
||||||
|
|
||||||
public class Vertex : IComparable<Vertex>
|
|
||||||
{
|
|
||||||
Vector3 vector;
|
|
||||||
|
|
||||||
public float X
|
|
||||||
{
|
|
||||||
get { return vector.X; }
|
|
||||||
set { vector.X = value; }
|
|
||||||
}
|
|
||||||
|
|
||||||
public float Y
|
|
||||||
{
|
|
||||||
get { return vector.Y; }
|
|
||||||
set { vector.Y = value; }
|
|
||||||
}
|
|
||||||
|
|
||||||
public float Z
|
|
||||||
{
|
|
||||||
get { return vector.Z; }
|
|
||||||
set { vector.Z = value; }
|
|
||||||
}
|
|
||||||
|
|
||||||
public Vertex(float x, float y, float z)
|
|
||||||
{
|
|
||||||
vector.X = x;
|
|
||||||
vector.Y = y;
|
|
||||||
vector.Z = z;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Vertex normalize()
|
|
||||||
{
|
|
||||||
float tlength = vector.Length();
|
|
||||||
if (tlength != 0f)
|
|
||||||
{
|
|
||||||
float mul = 1.0f / tlength;
|
|
||||||
return new Vertex(vector.X * mul, vector.Y * mul, vector.Z * mul);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
return new Vertex(0f, 0f, 0f);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public Vertex cross(Vertex v)
|
|
||||||
{
|
|
||||||
return new Vertex(vector.Y * v.Z - vector.Z * v.Y, vector.Z * v.X - vector.X * v.Z, vector.X * v.Y - vector.Y * v.X);
|
|
||||||
}
|
|
||||||
|
|
||||||
// disable warning: mono compiler moans about overloading
|
|
||||||
// operators hiding base operator but should not according to C#
|
|
||||||
// language spec
|
|
||||||
#pragma warning disable 0108
|
|
||||||
public static Vertex operator *(Vertex v, Quaternion q)
|
|
||||||
{
|
|
||||||
// From http://www.euclideanspace.com/maths/algebra/realNormedAlgebra/quaternions/transforms/
|
|
||||||
|
|
||||||
Vertex v2 = new Vertex(0f, 0f, 0f);
|
|
||||||
|
|
||||||
v2.X = q.W * q.W * v.X +
|
|
||||||
2f * q.Y * q.W * v.Z -
|
|
||||||
2f * q.Z * q.W * v.Y +
|
|
||||||
q.X * q.X * v.X +
|
|
||||||
2f * q.Y * q.X * v.Y +
|
|
||||||
2f * q.Z * q.X * v.Z -
|
|
||||||
q.Z * q.Z * v.X -
|
|
||||||
q.Y * q.Y * v.X;
|
|
||||||
|
|
||||||
v2.Y =
|
|
||||||
2f * q.X * q.Y * v.X +
|
|
||||||
q.Y * q.Y * v.Y +
|
|
||||||
2f * q.Z * q.Y * v.Z +
|
|
||||||
2f * q.W * q.Z * v.X -
|
|
||||||
q.Z * q.Z * v.Y +
|
|
||||||
q.W * q.W * v.Y -
|
|
||||||
2f * q.X * q.W * v.Z -
|
|
||||||
q.X * q.X * v.Y;
|
|
||||||
|
|
||||||
v2.Z =
|
|
||||||
2f * q.X * q.Z * v.X +
|
|
||||||
2f * q.Y * q.Z * v.Y +
|
|
||||||
q.Z * q.Z * v.Z -
|
|
||||||
2f * q.W * q.Y * v.X -
|
|
||||||
q.Y * q.Y * v.Z +
|
|
||||||
2f * q.W * q.X * v.Y -
|
|
||||||
q.X * q.X * v.Z +
|
|
||||||
q.W * q.W * v.Z;
|
|
||||||
|
|
||||||
return v2;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static Vertex operator +(Vertex v1, Vertex v2)
|
|
||||||
{
|
|
||||||
return new Vertex(v1.X + v2.X, v1.Y + v2.Y, v1.Z + v2.Z);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static Vertex operator -(Vertex v1, Vertex v2)
|
|
||||||
{
|
|
||||||
return new Vertex(v1.X - v2.X, v1.Y - v2.Y, v1.Z - v2.Z);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static Vertex operator *(Vertex v1, Vertex v2)
|
|
||||||
{
|
|
||||||
return new Vertex(v1.X * v2.X, v1.Y * v2.Y, v1.Z * v2.Z);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static Vertex operator +(Vertex v1, float am)
|
|
||||||
{
|
|
||||||
v1.X += am;
|
|
||||||
v1.Y += am;
|
|
||||||
v1.Z += am;
|
|
||||||
return v1;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static Vertex operator -(Vertex v1, float am)
|
|
||||||
{
|
|
||||||
v1.X -= am;
|
|
||||||
v1.Y -= am;
|
|
||||||
v1.Z -= am;
|
|
||||||
return v1;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static Vertex operator *(Vertex v1, float am)
|
|
||||||
{
|
|
||||||
v1.X *= am;
|
|
||||||
v1.Y *= am;
|
|
||||||
v1.Z *= am;
|
|
||||||
return v1;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static Vertex operator /(Vertex v1, float am)
|
|
||||||
{
|
|
||||||
if (am == 0f)
|
|
||||||
{
|
|
||||||
return new Vertex(0f,0f,0f);
|
|
||||||
}
|
|
||||||
float mul = 1.0f / am;
|
|
||||||
v1.X *= mul;
|
|
||||||
v1.Y *= mul;
|
|
||||||
v1.Z *= mul;
|
|
||||||
return v1;
|
|
||||||
}
|
|
||||||
#pragma warning restore 0108
|
|
||||||
|
|
||||||
|
|
||||||
public float dot(Vertex v)
|
|
||||||
{
|
|
||||||
return X * v.X + Y * v.Y + Z * v.Z;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Vertex(Vector3 v)
|
|
||||||
{
|
|
||||||
vector = v;
|
|
||||||
}
|
|
||||||
|
|
||||||
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 float Length()
|
|
||||||
{
|
|
||||||
return vector.Length();
|
|
||||||
}
|
|
||||||
|
|
||||||
public virtual bool Equals(Vertex v, float tolerance)
|
|
||||||
{
|
|
||||||
Vertex 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 = 6;
|
|
||||||
|
|
||||||
String s1 = X.ToString(nfi) + " " + Y.ToString(nfi) + " " + Z.ToString(nfi);
|
|
||||||
|
|
||||||
return s1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public class Triangle
|
|
||||||
{
|
|
||||||
public Vertex v1;
|
|
||||||
public Vertex v2;
|
|
||||||
public Vertex v3;
|
|
||||||
|
|
||||||
public Triangle(Vertex _v1, Vertex _v2, Vertex _v3)
|
|
||||||
{
|
|
||||||
v1 = _v1;
|
|
||||||
v2 = _v2;
|
|
||||||
v3 = _v3;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Triangle(float _v1x,float _v1y,float _v1z,
|
|
||||||
float _v2x,float _v2y,float _v2z,
|
|
||||||
float _v3x,float _v3y,float _v3z)
|
|
||||||
{
|
|
||||||
v1 = new Vertex(_v1x, _v1y, _v1z);
|
|
||||||
v2 = new Vertex(_v2x, _v2y, _v2z);
|
|
||||||
v3 = new Vertex(_v3x, _v3y, _v3z);
|
|
||||||
}
|
|
||||||
|
|
||||||
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 Vector3 getNormal()
|
|
||||||
{
|
|
||||||
// Vertices
|
|
||||||
|
|
||||||
// Vectors for edges
|
|
||||||
Vector3 e1;
|
|
||||||
Vector3 e2;
|
|
||||||
|
|
||||||
e1 = new Vector3(v1.X - v2.X, v1.Y - v2.Y, v1.Z - v2.Z);
|
|
||||||
e2 = new Vector3(v1.X - v3.X, v1.Y - v3.Y, v1.Z - v3.Z);
|
|
||||||
|
|
||||||
// Cross product for normal
|
|
||||||
Vector3 n = Vector3.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;
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,58 +0,0 @@
|
||||||
/*
|
|
||||||
* Copyright (c) Contributors, http://opensimulator.org/
|
|
||||||
* See CONTRIBUTORS.TXT for a full list of copyright holders.
|
|
||||||
*
|
|
||||||
* Redistribution and use in source and binary forms, with or without
|
|
||||||
* modification, are permitted provided that the following conditions are met:
|
|
||||||
* * Redistributions of source code must retain the above copyright
|
|
||||||
* notice, this list of conditions and the following disclaimer.
|
|
||||||
* * Redistributions in binary form must reproduce the above copyright
|
|
||||||
* notice, this list of conditions and the following disclaimer in the
|
|
||||||
* documentation and/or other materials provided with the distribution.
|
|
||||||
* * Neither the name of the OpenSimulator Project nor the
|
|
||||||
* names of its contributors may be used to endorse or promote products
|
|
||||||
* derived from this software without specific prior written permission.
|
|
||||||
*
|
|
||||||
* THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
|
|
||||||
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
|
||||||
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
|
||||||
* DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
|
|
||||||
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
|
||||||
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
|
||||||
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
|
||||||
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
|
||||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
|
||||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
||||||
*/
|
|
||||||
|
|
||||||
using System.Reflection;
|
|
||||||
using System.Runtime.InteropServices;
|
|
||||||
|
|
||||||
// Information about this assembly is defined by the following
|
|
||||||
// attributes.
|
|
||||||
//
|
|
||||||
// change them to the information which is associated with the assembly
|
|
||||||
// you compile.
|
|
||||||
|
|
||||||
[assembly : AssemblyTitle("OdePlugin")]
|
|
||||||
[assembly : AssemblyDescription("Ubit Variation")]
|
|
||||||
[assembly : AssemblyConfiguration("")]
|
|
||||||
[assembly : AssemblyCompany("http://opensimulator.org")]
|
|
||||||
[assembly : AssemblyProduct("OdePlugin")]
|
|
||||||
[assembly : AssemblyCopyright("Copyright (c) OpenSimulator.org Developers 2007-2009")]
|
|
||||||
[assembly : AssemblyTrademark("")]
|
|
||||||
[assembly : AssemblyCulture("")]
|
|
||||||
|
|
||||||
// This sets the default COM visibility of types in the assembly to invisible.
|
|
||||||
// If you need to expose a type to COM, use [ComVisible(true)] on that type.
|
|
||||||
|
|
||||||
[assembly : ComVisible(false)]
|
|
||||||
|
|
||||||
// The assembly version has following format :
|
|
||||||
//
|
|
||||||
// Major.Minor.Build.Revision
|
|
||||||
//
|
|
||||||
// You can specify all values by your own or you can build default build and revision
|
|
||||||
// numbers with the '*' character (the default):
|
|
||||||
|
|
||||||
[assembly : AssemblyVersion("0.6.5.*")]
|
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
|
@ -1,933 +0,0 @@
|
||||||
/*
|
|
||||||
* AJLDuarte 2012
|
|
||||||
*/
|
|
||||||
|
|
||||||
using System;
|
|
||||||
using System.Threading;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.IO;
|
|
||||||
using System.Reflection;
|
|
||||||
using System.Runtime.InteropServices;
|
|
||||||
using System.Text;
|
|
||||||
using OpenSim.Framework;
|
|
||||||
using OpenSim.Region.PhysicsModules.SharedBase;
|
|
||||||
using OdeAPI;
|
|
||||||
using log4net;
|
|
||||||
using Nini.Config;
|
|
||||||
using OpenMetaverse;
|
|
||||||
|
|
||||||
namespace OpenSim.Region.PhysicsModules.OdePlugin
|
|
||||||
{
|
|
||||||
public enum MeshState : byte
|
|
||||||
{
|
|
||||||
noNeed = 0,
|
|
||||||
|
|
||||||
loadingAsset = 1,
|
|
||||||
|
|
||||||
AssetOK = 0x0f, // 00001111
|
|
||||||
|
|
||||||
NeedMask = 0x30, // 00110000
|
|
||||||
needMesh = 0x10, // 00010000
|
|
||||||
needAsset = 0x20, // 00100000
|
|
||||||
|
|
||||||
FailMask = 0xC0, // 11000000
|
|
||||||
AssetFailed = 0x40, // 01000000
|
|
||||||
MeshFailed = 0x80, // 10000000
|
|
||||||
|
|
||||||
MeshNoColide = FailMask | needAsset
|
|
||||||
}
|
|
||||||
|
|
||||||
public enum meshWorkerCmnds : byte
|
|
||||||
{
|
|
||||||
nop = 0,
|
|
||||||
addnew,
|
|
||||||
changefull,
|
|
||||||
changesize,
|
|
||||||
changeshapetype,
|
|
||||||
getmesh,
|
|
||||||
}
|
|
||||||
|
|
||||||
public class ODEPhysRepData
|
|
||||||
{
|
|
||||||
public PhysicsActor actor;
|
|
||||||
public PrimitiveBaseShape pbs;
|
|
||||||
public IMesh mesh;
|
|
||||||
|
|
||||||
public Vector3 size;
|
|
||||||
public Vector3 OBB;
|
|
||||||
public Vector3 OBBOffset;
|
|
||||||
|
|
||||||
public float volume;
|
|
||||||
|
|
||||||
public byte shapetype;
|
|
||||||
public bool hasOBB;
|
|
||||||
public bool hasMeshVolume;
|
|
||||||
public MeshState meshState;
|
|
||||||
public UUID? assetID;
|
|
||||||
public meshWorkerCmnds comand;
|
|
||||||
}
|
|
||||||
|
|
||||||
public class ODEMeshWorker
|
|
||||||
{
|
|
||||||
|
|
||||||
private ILog m_log;
|
|
||||||
private OdeScene m_scene;
|
|
||||||
private IMesher m_mesher;
|
|
||||||
|
|
||||||
public bool meshSculptedPrim = true;
|
|
||||||
public bool forceSimplePrimMeshing = false;
|
|
||||||
public float meshSculptLOD = 32;
|
|
||||||
public float MeshSculptphysicalLOD = 32;
|
|
||||||
|
|
||||||
|
|
||||||
private OpenSim.Framework.BlockingQueue<ODEPhysRepData> createqueue = new OpenSim.Framework.BlockingQueue<ODEPhysRepData>();
|
|
||||||
private bool m_running;
|
|
||||||
|
|
||||||
private Thread m_thread;
|
|
||||||
|
|
||||||
public ODEMeshWorker(OdeScene pScene, ILog pLog, IMesher pMesher, IConfig pConfig)
|
|
||||||
{
|
|
||||||
m_scene = pScene;
|
|
||||||
m_log = pLog;
|
|
||||||
m_mesher = pMesher;
|
|
||||||
|
|
||||||
if (pConfig != null)
|
|
||||||
{
|
|
||||||
forceSimplePrimMeshing = pConfig.GetBoolean("force_simple_prim_meshing", forceSimplePrimMeshing);
|
|
||||||
meshSculptedPrim = pConfig.GetBoolean("mesh_sculpted_prim", meshSculptedPrim);
|
|
||||||
meshSculptLOD = pConfig.GetFloat("mesh_lod", meshSculptLOD);
|
|
||||||
MeshSculptphysicalLOD = pConfig.GetFloat("mesh_physical_lod", MeshSculptphysicalLOD);
|
|
||||||
}
|
|
||||||
m_running = true;
|
|
||||||
m_thread = new Thread(DoWork);
|
|
||||||
m_thread.Name = "OdeMeshWorker";
|
|
||||||
m_thread.Start();
|
|
||||||
}
|
|
||||||
|
|
||||||
private void DoWork()
|
|
||||||
{
|
|
||||||
m_mesher.ExpireFileCache();
|
|
||||||
|
|
||||||
while(m_running)
|
|
||||||
{
|
|
||||||
ODEPhysRepData nextRep = createqueue.Dequeue();
|
|
||||||
if(!m_running)
|
|
||||||
return;
|
|
||||||
if (nextRep == null)
|
|
||||||
continue;
|
|
||||||
if (m_scene.haveActor(nextRep.actor))
|
|
||||||
{
|
|
||||||
switch (nextRep.comand)
|
|
||||||
{
|
|
||||||
case meshWorkerCmnds.changefull:
|
|
||||||
case meshWorkerCmnds.changeshapetype:
|
|
||||||
case meshWorkerCmnds.changesize:
|
|
||||||
GetMesh(nextRep);
|
|
||||||
if (CreateActorPhysRep(nextRep) && m_scene.haveActor(nextRep.actor))
|
|
||||||
m_scene.AddChange(nextRep.actor, changes.PhysRepData, nextRep);
|
|
||||||
break;
|
|
||||||
case meshWorkerCmnds.getmesh:
|
|
||||||
DoRepDataGetMesh(nextRep);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void Stop()
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
m_thread.Abort();
|
|
||||||
createqueue.Clear();
|
|
||||||
}
|
|
||||||
catch
|
|
||||||
{
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void ChangeActorPhysRep(PhysicsActor actor, PrimitiveBaseShape pbs,
|
|
||||||
Vector3 size, byte shapetype)
|
|
||||||
{
|
|
||||||
ODEPhysRepData repData = new ODEPhysRepData();
|
|
||||||
repData.actor = actor;
|
|
||||||
repData.pbs = pbs;
|
|
||||||
repData.size = size;
|
|
||||||
repData.shapetype = shapetype;
|
|
||||||
|
|
||||||
CheckMesh(repData);
|
|
||||||
CalcVolumeData(repData);
|
|
||||||
m_scene.AddChange(actor, changes.PhysRepData, repData);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
public ODEPhysRepData NewActorPhysRep(PhysicsActor actor, PrimitiveBaseShape pbs,
|
|
||||||
Vector3 size, byte shapetype)
|
|
||||||
{
|
|
||||||
ODEPhysRepData repData = new ODEPhysRepData();
|
|
||||||
repData.actor = actor;
|
|
||||||
repData.pbs = pbs;
|
|
||||||
repData.size = size;
|
|
||||||
repData.shapetype = shapetype;
|
|
||||||
|
|
||||||
CheckMesh(repData);
|
|
||||||
CalcVolumeData(repData);
|
|
||||||
m_scene.AddChange(actor, changes.AddPhysRep, repData);
|
|
||||||
return repData;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void RequestMesh(ODEPhysRepData repData)
|
|
||||||
{
|
|
||||||
repData.mesh = null;
|
|
||||||
|
|
||||||
if (repData.meshState == MeshState.needAsset)
|
|
||||||
{
|
|
||||||
PrimitiveBaseShape pbs = repData.pbs;
|
|
||||||
|
|
||||||
// check if we got outdated
|
|
||||||
|
|
||||||
if (!pbs.SculptEntry || pbs.SculptTexture == UUID.Zero)
|
|
||||||
{
|
|
||||||
repData.meshState = MeshState.noNeed;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
repData.assetID = pbs.SculptTexture;
|
|
||||||
repData.meshState = MeshState.loadingAsset;
|
|
||||||
|
|
||||||
repData.comand = meshWorkerCmnds.getmesh;
|
|
||||||
createqueue.Enqueue(repData);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// creates and prepares a mesh to use and calls parameters estimation
|
|
||||||
public bool CreateActorPhysRep(ODEPhysRepData repData)
|
|
||||||
{
|
|
||||||
IMesh mesh = repData.mesh;
|
|
||||||
|
|
||||||
if (mesh != null)
|
|
||||||
{
|
|
||||||
IntPtr vertices, indices;
|
|
||||||
int vertexCount, indexCount;
|
|
||||||
int vertexStride, triStride;
|
|
||||||
|
|
||||||
mesh.getVertexListAsPtrToFloatArray(out vertices, out vertexStride, out vertexCount);
|
|
||||||
mesh.getIndexListAsPtrToIntArray(out indices, out triStride, out indexCount);
|
|
||||||
|
|
||||||
if (vertexCount == 0 || indexCount == 0)
|
|
||||||
{
|
|
||||||
m_log.WarnFormat("[PHYSICS]: Invalid mesh data on prim {0} mesh UUID {1}",
|
|
||||||
repData.actor.Name, repData.pbs.SculptTexture.ToString());
|
|
||||||
repData.meshState = MeshState.MeshFailed;
|
|
||||||
repData.hasOBB = false;
|
|
||||||
repData.mesh = null;
|
|
||||||
m_scene.mesher.ReleaseMesh(mesh);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
repData.OBBOffset = mesh.GetCentroid();
|
|
||||||
repData.OBB = mesh.GetOBB();
|
|
||||||
repData.hasOBB = true;
|
|
||||||
mesh.releaseSourceMeshData();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
CalcVolumeData(repData);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void AssetLoaded(ODEPhysRepData repData)
|
|
||||||
{
|
|
||||||
if (m_scene.haveActor(repData.actor))
|
|
||||||
{
|
|
||||||
if (needsMeshing(repData.pbs)) // no need for pbs now?
|
|
||||||
{
|
|
||||||
repData.comand = meshWorkerCmnds.changefull;
|
|
||||||
createqueue.Enqueue(repData);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
repData.pbs.SculptData = Utils.EmptyBytes;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void DoRepDataGetMesh(ODEPhysRepData repData)
|
|
||||||
{
|
|
||||||
if (!repData.pbs.SculptEntry)
|
|
||||||
return;
|
|
||||||
|
|
||||||
if (repData.meshState != MeshState.loadingAsset)
|
|
||||||
return;
|
|
||||||
|
|
||||||
if (repData.assetID == null || repData.assetID == UUID.Zero)
|
|
||||||
return;
|
|
||||||
|
|
||||||
if (repData.assetID != repData.pbs.SculptTexture)
|
|
||||||
return;
|
|
||||||
|
|
||||||
// check if it is in cache
|
|
||||||
GetMesh(repData);
|
|
||||||
if (repData.meshState != MeshState.needAsset)
|
|
||||||
{
|
|
||||||
CreateActorPhysRep(repData);
|
|
||||||
m_scene.AddChange(repData.actor, changes.PhysRepData, repData);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
RequestAssetDelegate assetProvider = m_scene.RequestAssetMethod;
|
|
||||||
if (assetProvider == null)
|
|
||||||
return;
|
|
||||||
ODEAssetRequest asr = new ODEAssetRequest(this, assetProvider, repData, m_log);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Routine to figure out if we need to mesh this prim with our mesher
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="pbs"></param>
|
|
||||||
/// <returns></returns>
|
|
||||||
public bool needsMeshing(PrimitiveBaseShape pbs)
|
|
||||||
{
|
|
||||||
// check sculpts or meshs
|
|
||||||
if (pbs.SculptEntry)
|
|
||||||
{
|
|
||||||
if (meshSculptedPrim)
|
|
||||||
return true;
|
|
||||||
|
|
||||||
if (pbs.SculptType == (byte)SculptType.Mesh) // always do meshs
|
|
||||||
return true;
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (forceSimplePrimMeshing)
|
|
||||||
return true;
|
|
||||||
|
|
||||||
// if it's a standard box or sphere with no cuts, hollows, twist or top shear, return false since ODE can use an internal representation for the prim
|
|
||||||
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// following code doesn't give meshs to boxes and spheres ever
|
|
||||||
// and it's odd.. so for now just return true if asked to force meshs
|
|
||||||
// hopefully mesher will fail if doesn't suport so things still get basic boxes
|
|
||||||
|
|
||||||
int iPropertiesNotSupportedDefault = 0;
|
|
||||||
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
|
|
||||||
// see if we need a mesh and if so if we have a cached one
|
|
||||||
// called with a new repData
|
|
||||||
public void CheckMesh(ODEPhysRepData repData)
|
|
||||||
{
|
|
||||||
PhysicsActor actor = repData.actor;
|
|
||||||
PrimitiveBaseShape pbs = repData.pbs;
|
|
||||||
|
|
||||||
if (!needsMeshing(pbs))
|
|
||||||
{
|
|
||||||
repData.meshState = MeshState.noNeed;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
IMesh mesh = null;
|
|
||||||
|
|
||||||
Vector3 size = repData.size;
|
|
||||||
byte shapetype = repData.shapetype;
|
|
||||||
|
|
||||||
bool convex;
|
|
||||||
|
|
||||||
int clod = (int)LevelOfDetail.High;
|
|
||||||
if (shapetype == 0)
|
|
||||||
convex = false;
|
|
||||||
else
|
|
||||||
{
|
|
||||||
convex = true;
|
|
||||||
if (pbs.SculptType != (byte)SculptType.Mesh)
|
|
||||||
clod = (int)LevelOfDetail.Low;
|
|
||||||
}
|
|
||||||
|
|
||||||
mesh = m_mesher.GetMesh(actor.Name, pbs, size, clod, true, convex);
|
|
||||||
|
|
||||||
if (mesh == null)
|
|
||||||
{
|
|
||||||
if (pbs.SculptEntry)
|
|
||||||
{
|
|
||||||
if (pbs.SculptTexture != null && pbs.SculptTexture != UUID.Zero)
|
|
||||||
{
|
|
||||||
repData.assetID = pbs.SculptTexture;
|
|
||||||
repData.meshState = MeshState.needAsset;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
repData.meshState = MeshState.MeshFailed;
|
|
||||||
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
repData.meshState = MeshState.needMesh;
|
|
||||||
mesh = m_mesher.CreateMesh(actor.Name, pbs, size, clod, true, convex, true);
|
|
||||||
if (mesh == null)
|
|
||||||
{
|
|
||||||
repData.meshState = MeshState.MeshFailed;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
repData.meshState = MeshState.AssetOK;
|
|
||||||
repData.mesh = mesh;
|
|
||||||
|
|
||||||
if (pbs.SculptEntry)
|
|
||||||
{
|
|
||||||
repData.assetID = pbs.SculptTexture;
|
|
||||||
}
|
|
||||||
|
|
||||||
pbs.SculptData = Utils.EmptyBytes;
|
|
||||||
return ;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void GetMesh(ODEPhysRepData repData)
|
|
||||||
{
|
|
||||||
PhysicsActor actor = repData.actor;
|
|
||||||
|
|
||||||
PrimitiveBaseShape pbs = repData.pbs;
|
|
||||||
|
|
||||||
repData.mesh = null;
|
|
||||||
repData.hasOBB = false;
|
|
||||||
|
|
||||||
if (!needsMeshing(pbs))
|
|
||||||
{
|
|
||||||
repData.meshState = MeshState.noNeed;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (repData.meshState == MeshState.MeshFailed)
|
|
||||||
return;
|
|
||||||
|
|
||||||
if (pbs.SculptEntry)
|
|
||||||
{
|
|
||||||
if (repData.meshState == MeshState.AssetFailed)
|
|
||||||
{
|
|
||||||
if (pbs.SculptTexture == repData.assetID)
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
repData.meshState = MeshState.noNeed;
|
|
||||||
|
|
||||||
IMesh mesh = null;
|
|
||||||
Vector3 size = repData.size;
|
|
||||||
byte shapetype = repData.shapetype;
|
|
||||||
|
|
||||||
bool convex;
|
|
||||||
int clod = (int)LevelOfDetail.High;
|
|
||||||
if (shapetype == 0)
|
|
||||||
convex = false;
|
|
||||||
else
|
|
||||||
{
|
|
||||||
convex = true;
|
|
||||||
if (pbs.SculptType != (byte)SculptType.Mesh)
|
|
||||||
clod = (int)LevelOfDetail.Low;
|
|
||||||
}
|
|
||||||
|
|
||||||
mesh = m_mesher.CreateMesh(actor.Name, pbs, size, clod, true, convex, true);
|
|
||||||
|
|
||||||
if (mesh == null)
|
|
||||||
{
|
|
||||||
if (pbs.SculptEntry)
|
|
||||||
{
|
|
||||||
if (pbs.SculptTexture == UUID.Zero)
|
|
||||||
return;
|
|
||||||
|
|
||||||
repData.assetID = pbs.SculptTexture;
|
|
||||||
|
|
||||||
if (pbs.SculptData == null || pbs.SculptData.Length == 0)
|
|
||||||
{
|
|
||||||
repData.meshState = MeshState.needAsset;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
repData.mesh = mesh;
|
|
||||||
repData.pbs.SculptData = Utils.EmptyBytes;
|
|
||||||
|
|
||||||
if (mesh == null)
|
|
||||||
{
|
|
||||||
if (pbs.SculptEntry)
|
|
||||||
repData.meshState = MeshState.AssetFailed;
|
|
||||||
else
|
|
||||||
repData.meshState = MeshState.MeshFailed;
|
|
||||||
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
repData.meshState = MeshState.AssetOK;
|
|
||||||
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
private void CalculateBasicPrimVolume(ODEPhysRepData repData)
|
|
||||||
{
|
|
||||||
PrimitiveBaseShape _pbs = repData.pbs;
|
|
||||||
Vector3 _size = repData.size;
|
|
||||||
|
|
||||||
float volume = _size.X * _size.Y * _size.Z; // default
|
|
||||||
float tmp;
|
|
||||||
|
|
||||||
float hollowAmount = (float)_pbs.ProfileHollow * 2.0e-5f;
|
|
||||||
float hollowVolume = hollowAmount * hollowAmount;
|
|
||||||
|
|
||||||
switch (_pbs.ProfileShape)
|
|
||||||
{
|
|
||||||
case ProfileShape.Square:
|
|
||||||
// default box
|
|
||||||
|
|
||||||
if (_pbs.PathCurve == (byte)Extrusion.Straight)
|
|
||||||
{
|
|
||||||
if (hollowAmount > 0.0)
|
|
||||||
{
|
|
||||||
switch (_pbs.HollowShape)
|
|
||||||
{
|
|
||||||
case HollowShape.Square:
|
|
||||||
case HollowShape.Same:
|
|
||||||
break;
|
|
||||||
|
|
||||||
case HollowShape.Circle:
|
|
||||||
|
|
||||||
hollowVolume *= 0.78539816339f;
|
|
||||||
break;
|
|
||||||
|
|
||||||
case HollowShape.Triangle:
|
|
||||||
|
|
||||||
hollowVolume *= (0.5f * .5f);
|
|
||||||
break;
|
|
||||||
|
|
||||||
default:
|
|
||||||
hollowVolume = 0;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
volume *= (1.0f - hollowVolume);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
else if (_pbs.PathCurve == (byte)Extrusion.Curve1)
|
|
||||||
{
|
|
||||||
//a tube
|
|
||||||
|
|
||||||
volume *= 0.78539816339e-2f * (float)(200 - _pbs.PathScaleX);
|
|
||||||
tmp = 1.0f - 2.0e-2f * (float)(200 - _pbs.PathScaleY);
|
|
||||||
volume -= volume * tmp * tmp;
|
|
||||||
|
|
||||||
if (hollowAmount > 0.0)
|
|
||||||
{
|
|
||||||
hollowVolume *= hollowAmount;
|
|
||||||
|
|
||||||
switch (_pbs.HollowShape)
|
|
||||||
{
|
|
||||||
case HollowShape.Square:
|
|
||||||
case HollowShape.Same:
|
|
||||||
break;
|
|
||||||
|
|
||||||
case HollowShape.Circle:
|
|
||||||
hollowVolume *= 0.78539816339f;
|
|
||||||
break;
|
|
||||||
|
|
||||||
case HollowShape.Triangle:
|
|
||||||
hollowVolume *= 0.5f * 0.5f;
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
hollowVolume = 0;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
volume *= (1.0f - hollowVolume);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
break;
|
|
||||||
|
|
||||||
case ProfileShape.Circle:
|
|
||||||
|
|
||||||
if (_pbs.PathCurve == (byte)Extrusion.Straight)
|
|
||||||
{
|
|
||||||
volume *= 0.78539816339f; // elipse base
|
|
||||||
|
|
||||||
if (hollowAmount > 0.0)
|
|
||||||
{
|
|
||||||
switch (_pbs.HollowShape)
|
|
||||||
{
|
|
||||||
case HollowShape.Same:
|
|
||||||
case HollowShape.Circle:
|
|
||||||
break;
|
|
||||||
|
|
||||||
case HollowShape.Square:
|
|
||||||
hollowVolume *= 0.5f * 2.5984480504799f;
|
|
||||||
break;
|
|
||||||
|
|
||||||
case HollowShape.Triangle:
|
|
||||||
hollowVolume *= .5f * 1.27323954473516f;
|
|
||||||
break;
|
|
||||||
|
|
||||||
default:
|
|
||||||
hollowVolume = 0;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
volume *= (1.0f - hollowVolume);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
else if (_pbs.PathCurve == (byte)Extrusion.Curve1)
|
|
||||||
{
|
|
||||||
volume *= 0.61685027506808491367715568749226e-2f * (float)(200 - _pbs.PathScaleX);
|
|
||||||
tmp = 1.0f - .02f * (float)(200 - _pbs.PathScaleY);
|
|
||||||
volume *= (1.0f - tmp * tmp);
|
|
||||||
|
|
||||||
if (hollowAmount > 0.0)
|
|
||||||
{
|
|
||||||
|
|
||||||
// calculate the hollow volume by it's shape compared to the prim shape
|
|
||||||
hollowVolume *= hollowAmount;
|
|
||||||
|
|
||||||
switch (_pbs.HollowShape)
|
|
||||||
{
|
|
||||||
case HollowShape.Same:
|
|
||||||
case HollowShape.Circle:
|
|
||||||
break;
|
|
||||||
|
|
||||||
case HollowShape.Square:
|
|
||||||
hollowVolume *= 0.5f * 2.5984480504799f;
|
|
||||||
break;
|
|
||||||
|
|
||||||
case HollowShape.Triangle:
|
|
||||||
hollowVolume *= .5f * 1.27323954473516f;
|
|
||||||
break;
|
|
||||||
|
|
||||||
default:
|
|
||||||
hollowVolume = 0;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
volume *= (1.0f - hollowVolume);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
|
|
||||||
case ProfileShape.HalfCircle:
|
|
||||||
if (_pbs.PathCurve == (byte)Extrusion.Curve1)
|
|
||||||
{
|
|
||||||
volume *= 0.5236f;
|
|
||||||
|
|
||||||
if (hollowAmount > 0.0)
|
|
||||||
{
|
|
||||||
hollowVolume *= hollowAmount;
|
|
||||||
|
|
||||||
switch (_pbs.HollowShape)
|
|
||||||
{
|
|
||||||
case HollowShape.Circle:
|
|
||||||
case HollowShape.Triangle: // diference in sl is minor and odd
|
|
||||||
case HollowShape.Same:
|
|
||||||
break;
|
|
||||||
|
|
||||||
case HollowShape.Square:
|
|
||||||
hollowVolume *= 0.909f;
|
|
||||||
break;
|
|
||||||
|
|
||||||
// case HollowShape.Triangle:
|
|
||||||
// hollowVolume *= .827f;
|
|
||||||
// break;
|
|
||||||
default:
|
|
||||||
hollowVolume = 0;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
volume *= (1.0f - hollowVolume);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
|
|
||||||
case ProfileShape.EquilateralTriangle:
|
|
||||||
|
|
||||||
if (_pbs.PathCurve == (byte)Extrusion.Straight)
|
|
||||||
{
|
|
||||||
volume *= 0.32475953f;
|
|
||||||
|
|
||||||
if (hollowAmount > 0.0)
|
|
||||||
{
|
|
||||||
|
|
||||||
// calculate the hollow volume by it's shape compared to the prim shape
|
|
||||||
switch (_pbs.HollowShape)
|
|
||||||
{
|
|
||||||
case HollowShape.Same:
|
|
||||||
case HollowShape.Triangle:
|
|
||||||
hollowVolume *= .25f;
|
|
||||||
break;
|
|
||||||
|
|
||||||
case HollowShape.Square:
|
|
||||||
hollowVolume *= 0.499849f * 3.07920140172638f;
|
|
||||||
break;
|
|
||||||
|
|
||||||
case HollowShape.Circle:
|
|
||||||
// Hollow shape is a perfect cyllinder in respect to the cube's scale
|
|
||||||
// Cyllinder hollow volume calculation
|
|
||||||
|
|
||||||
hollowVolume *= 0.1963495f * 3.07920140172638f;
|
|
||||||
break;
|
|
||||||
|
|
||||||
default:
|
|
||||||
hollowVolume = 0;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
volume *= (1.0f - hollowVolume);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else if (_pbs.PathCurve == (byte)Extrusion.Curve1)
|
|
||||||
{
|
|
||||||
volume *= 0.32475953f;
|
|
||||||
volume *= 0.01f * (float)(200 - _pbs.PathScaleX);
|
|
||||||
tmp = 1.0f - .02f * (float)(200 - _pbs.PathScaleY);
|
|
||||||
volume *= (1.0f - tmp * tmp);
|
|
||||||
|
|
||||||
if (hollowAmount > 0.0)
|
|
||||||
{
|
|
||||||
|
|
||||||
hollowVolume *= hollowAmount;
|
|
||||||
|
|
||||||
switch (_pbs.HollowShape)
|
|
||||||
{
|
|
||||||
case HollowShape.Same:
|
|
||||||
case HollowShape.Triangle:
|
|
||||||
hollowVolume *= .25f;
|
|
||||||
break;
|
|
||||||
|
|
||||||
case HollowShape.Square:
|
|
||||||
hollowVolume *= 0.499849f * 3.07920140172638f;
|
|
||||||
break;
|
|
||||||
|
|
||||||
case HollowShape.Circle:
|
|
||||||
|
|
||||||
hollowVolume *= 0.1963495f * 3.07920140172638f;
|
|
||||||
break;
|
|
||||||
|
|
||||||
default:
|
|
||||||
hollowVolume = 0;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
volume *= (1.0f - hollowVolume);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
|
|
||||||
default:
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
float taperX1;
|
|
||||||
float taperY1;
|
|
||||||
float taperX;
|
|
||||||
float taperY;
|
|
||||||
float pathBegin;
|
|
||||||
float pathEnd;
|
|
||||||
float profileBegin;
|
|
||||||
float profileEnd;
|
|
||||||
|
|
||||||
if (_pbs.PathCurve == (byte)Extrusion.Straight || _pbs.PathCurve == (byte)Extrusion.Flexible)
|
|
||||||
{
|
|
||||||
taperX1 = _pbs.PathScaleX * 0.01f;
|
|
||||||
if (taperX1 > 1.0f)
|
|
||||||
taperX1 = 2.0f - taperX1;
|
|
||||||
taperX = 1.0f - taperX1;
|
|
||||||
|
|
||||||
taperY1 = _pbs.PathScaleY * 0.01f;
|
|
||||||
if (taperY1 > 1.0f)
|
|
||||||
taperY1 = 2.0f - taperY1;
|
|
||||||
taperY = 1.0f - taperY1;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
taperX = _pbs.PathTaperX * 0.01f;
|
|
||||||
if (taperX < 0.0f)
|
|
||||||
taperX = -taperX;
|
|
||||||
taperX1 = 1.0f - taperX;
|
|
||||||
|
|
||||||
taperY = _pbs.PathTaperY * 0.01f;
|
|
||||||
if (taperY < 0.0f)
|
|
||||||
taperY = -taperY;
|
|
||||||
taperY1 = 1.0f - taperY;
|
|
||||||
}
|
|
||||||
|
|
||||||
volume *= (taperX1 * taperY1 + 0.5f * (taperX1 * taperY + taperX * taperY1) + 0.3333333333f * taperX * taperY);
|
|
||||||
|
|
||||||
pathBegin = (float)_pbs.PathBegin * 2.0e-5f;
|
|
||||||
pathEnd = 1.0f - (float)_pbs.PathEnd * 2.0e-5f;
|
|
||||||
volume *= (pathEnd - pathBegin);
|
|
||||||
|
|
||||||
// this is crude aproximation
|
|
||||||
profileBegin = (float)_pbs.ProfileBegin * 2.0e-5f;
|
|
||||||
profileEnd = 1.0f - (float)_pbs.ProfileEnd * 2.0e-5f;
|
|
||||||
volume *= (profileEnd - profileBegin);
|
|
||||||
|
|
||||||
repData.volume = volume;
|
|
||||||
}
|
|
||||||
|
|
||||||
private void CalcVolumeData(ODEPhysRepData repData)
|
|
||||||
{
|
|
||||||
if (repData.hasOBB)
|
|
||||||
{
|
|
||||||
Vector3 OBB = repData.OBB;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
Vector3 OBB = repData.size;
|
|
||||||
OBB.X *= 0.5f;
|
|
||||||
OBB.Y *= 0.5f;
|
|
||||||
OBB.Z *= 0.5f;
|
|
||||||
|
|
||||||
repData.OBB = OBB;
|
|
||||||
repData.OBBOffset = Vector3.Zero;
|
|
||||||
}
|
|
||||||
|
|
||||||
CalculateBasicPrimVolume(repData);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public class ODEAssetRequest
|
|
||||||
{
|
|
||||||
ODEMeshWorker m_worker;
|
|
||||||
private ILog m_log;
|
|
||||||
ODEPhysRepData repData;
|
|
||||||
|
|
||||||
public ODEAssetRequest(ODEMeshWorker pWorker, RequestAssetDelegate provider,
|
|
||||||
ODEPhysRepData pRepData, ILog plog)
|
|
||||||
{
|
|
||||||
m_worker = pWorker;
|
|
||||||
m_log = plog;
|
|
||||||
repData = pRepData;
|
|
||||||
|
|
||||||
repData.meshState = MeshState.AssetFailed;
|
|
||||||
if (provider == null)
|
|
||||||
return;
|
|
||||||
|
|
||||||
if (repData.assetID == null)
|
|
||||||
return;
|
|
||||||
|
|
||||||
UUID assetID = (UUID) repData.assetID;
|
|
||||||
if (assetID == UUID.Zero)
|
|
||||||
return;
|
|
||||||
|
|
||||||
repData.meshState = MeshState.loadingAsset;
|
|
||||||
provider(assetID, ODEassetReceived);
|
|
||||||
}
|
|
||||||
|
|
||||||
void ODEassetReceived(AssetBase asset)
|
|
||||||
{
|
|
||||||
repData.meshState = MeshState.AssetFailed;
|
|
||||||
if (asset != null)
|
|
||||||
{
|
|
||||||
if (asset.Data != null && asset.Data.Length > 0)
|
|
||||||
{
|
|
||||||
repData.meshState = MeshState.noNeed;
|
|
||||||
|
|
||||||
if (!repData.pbs.SculptEntry)
|
|
||||||
return;
|
|
||||||
if (repData.pbs.SculptTexture != repData.assetID)
|
|
||||||
return;
|
|
||||||
|
|
||||||
// repData.pbs.SculptData = new byte[asset.Data.Length];
|
|
||||||
// asset.Data.CopyTo(repData.pbs.SculptData,0);
|
|
||||||
repData.pbs.SculptData = asset.Data;
|
|
||||||
repData.meshState = MeshState.AssetOK;
|
|
||||||
m_worker.AssetLoaded(repData);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
m_log.WarnFormat("[PHYSICS]: asset provider returned invalid mesh data for prim {0} asset UUID {1}.",
|
|
||||||
repData.actor.Name, asset.ID.ToString());
|
|
||||||
}
|
|
||||||
else
|
|
||||||
m_log.WarnFormat("[PHYSICS]: asset provider returned null asset fo mesh of prim {0}.",
|
|
||||||
repData.actor.Name);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
File diff suppressed because it is too large
Load Diff
|
@ -1,683 +0,0 @@
|
||||||
/*
|
|
||||||
* Copyright (c) Contributors, http://opensimulator.org/
|
|
||||||
* See CONTRIBUTORS.TXT for a full list of copyright holders.
|
|
||||||
*
|
|
||||||
* Redistribution and use in source and binary forms, with or without
|
|
||||||
* modification, are permitted provided that the following conditions are met:
|
|
||||||
* * Redistributions of source code must retain the above copyright
|
|
||||||
* notice, this list of conditions and the following disclaimer.
|
|
||||||
* * Redistributions in binary form must reproduce the above copyright
|
|
||||||
* notice, this list of conditions and the following disclaimer in the
|
|
||||||
* documentation and/or other materials provided with the distribution.
|
|
||||||
* * Neither the name of the OpenSimulator Project nor the
|
|
||||||
* names of its contributors may be used to endorse or promote products
|
|
||||||
* derived from this software without specific prior written permission.
|
|
||||||
*
|
|
||||||
* THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
|
|
||||||
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
|
||||||
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
|
||||||
* DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
|
|
||||||
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
|
||||||
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
|
||||||
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
|
||||||
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
|
||||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
|
||||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
||||||
*/
|
|
||||||
|
|
||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Reflection;
|
|
||||||
using System.Runtime.InteropServices;
|
|
||||||
using System.Text;
|
|
||||||
using OpenSim.Framework;
|
|
||||||
using OpenSim.Region.PhysicsModules.SharedBase;
|
|
||||||
using OdeAPI;
|
|
||||||
using log4net;
|
|
||||||
using OpenMetaverse;
|
|
||||||
|
|
||||||
namespace OpenSim.Region.PhysicsModules.OdePlugin
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// Processes raycast requests as ODE is in a state to be able to do them.
|
|
||||||
/// This ensures that it's thread safe and there will be no conflicts.
|
|
||||||
/// Requests get returned by a different thread then they were requested by.
|
|
||||||
/// </summary>
|
|
||||||
public class ODERayCastRequestManager
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// Pending ray requests
|
|
||||||
/// </summary>
|
|
||||||
protected OpenSim.Framework.LocklessQueue<ODERayRequest> m_PendingRequests = new OpenSim.Framework.LocklessQueue<ODERayRequest>();
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Scene that created this object.
|
|
||||||
/// </summary>
|
|
||||||
private OdeScene m_scene;
|
|
||||||
|
|
||||||
IntPtr ray; // the ray. we only need one for our lifetime
|
|
||||||
IntPtr Sphere;
|
|
||||||
IntPtr Box;
|
|
||||||
IntPtr Plane;
|
|
||||||
|
|
||||||
private int CollisionContactGeomsPerTest = 25;
|
|
||||||
private const int DefaultMaxCount = 25;
|
|
||||||
private const int MaxTimePerCallMS = 30;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// ODE near callback delegate
|
|
||||||
/// </summary>
|
|
||||||
private d.NearCallback nearCallback;
|
|
||||||
private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
|
|
||||||
private List<ContactResult> m_contactResults = new List<ContactResult>();
|
|
||||||
private RayFilterFlags CurrentRayFilter;
|
|
||||||
private int CurrentMaxCount;
|
|
||||||
|
|
||||||
public ODERayCastRequestManager(OdeScene pScene)
|
|
||||||
{
|
|
||||||
m_scene = pScene;
|
|
||||||
nearCallback = near;
|
|
||||||
ray = d.CreateRay(IntPtr.Zero, 1.0f);
|
|
||||||
d.GeomSetCategoryBits(ray, 0);
|
|
||||||
Box = d.CreateBox(IntPtr.Zero, 1.0f, 1.0f, 1.0f);
|
|
||||||
d.GeomSetCategoryBits(Box, 0);
|
|
||||||
Sphere = d.CreateSphere(IntPtr.Zero,1.0f);
|
|
||||||
d.GeomSetCategoryBits(Sphere, 0);
|
|
||||||
Plane = d.CreatePlane(IntPtr.Zero, 0f,0f,1f,1f);
|
|
||||||
d.GeomSetCategoryBits(Sphere, 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void QueueRequest(ODERayRequest req)
|
|
||||||
{
|
|
||||||
if (req.Count == 0)
|
|
||||||
req.Count = DefaultMaxCount;
|
|
||||||
|
|
||||||
m_PendingRequests.Enqueue(req);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Process all queued raycast requests
|
|
||||||
/// </summary>
|
|
||||||
/// <returns>Time in MS the raycasts took to process.</returns>
|
|
||||||
public int ProcessQueuedRequests()
|
|
||||||
{
|
|
||||||
|
|
||||||
if (m_PendingRequests.Count <= 0)
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
if (m_scene.ContactgeomsArray == IntPtr.Zero || ray == IntPtr.Zero)
|
|
||||||
// oops something got wrong or scene isn't ready still
|
|
||||||
{
|
|
||||||
m_PendingRequests.Clear();
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
int time = Util.EnvironmentTickCount();
|
|
||||||
|
|
||||||
ODERayRequest req;
|
|
||||||
int closestHit;
|
|
||||||
int backfacecull;
|
|
||||||
CollisionCategories catflags;
|
|
||||||
|
|
||||||
while (m_PendingRequests.Dequeue(out req))
|
|
||||||
{
|
|
||||||
if (req.callbackMethod != null)
|
|
||||||
{
|
|
||||||
IntPtr geom = IntPtr.Zero;
|
|
||||||
if (req.actor != null)
|
|
||||||
{
|
|
||||||
if (m_scene.haveActor(req.actor))
|
|
||||||
{
|
|
||||||
if (req.actor is OdePrim)
|
|
||||||
geom = ((OdePrim)req.actor).prim_geom;
|
|
||||||
else if (req.actor is OdeCharacter)
|
|
||||||
geom = ((OdePrim)req.actor).prim_geom;
|
|
||||||
}
|
|
||||||
if (geom == IntPtr.Zero)
|
|
||||||
{
|
|
||||||
NoContacts(req);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
CurrentRayFilter = req.filter;
|
|
||||||
CurrentMaxCount = req.Count;
|
|
||||||
|
|
||||||
CollisionContactGeomsPerTest = req.Count & 0xffff;
|
|
||||||
|
|
||||||
closestHit = ((CurrentRayFilter & RayFilterFlags.ClosestHit) == 0 ? 0 : 1);
|
|
||||||
backfacecull = ((CurrentRayFilter & RayFilterFlags.BackFaceCull) == 0 ? 0 : 1);
|
|
||||||
|
|
||||||
if (req.callbackMethod is ProbeBoxCallback)
|
|
||||||
{
|
|
||||||
if (CollisionContactGeomsPerTest > 80)
|
|
||||||
CollisionContactGeomsPerTest = 80;
|
|
||||||
d.GeomBoxSetLengths(Box, req.Normal.X, req.Normal.Y, req.Normal.Z);
|
|
||||||
d.GeomSetPosition(Box, req.Origin.X, req.Origin.Y, req.Origin.Z);
|
|
||||||
d.Quaternion qtmp;
|
|
||||||
qtmp.X = req.orientation.X;
|
|
||||||
qtmp.Y = req.orientation.Y;
|
|
||||||
qtmp.Z = req.orientation.Z;
|
|
||||||
qtmp.W = req.orientation.W;
|
|
||||||
d.GeomSetQuaternion(Box, ref qtmp);
|
|
||||||
}
|
|
||||||
else if (req.callbackMethod is ProbeSphereCallback)
|
|
||||||
{
|
|
||||||
if (CollisionContactGeomsPerTest > 80)
|
|
||||||
CollisionContactGeomsPerTest = 80;
|
|
||||||
|
|
||||||
d.GeomSphereSetRadius(Sphere, req.length);
|
|
||||||
d.GeomSetPosition(Sphere, req.Origin.X, req.Origin.Y, req.Origin.Z);
|
|
||||||
}
|
|
||||||
else if (req.callbackMethod is ProbePlaneCallback)
|
|
||||||
{
|
|
||||||
if (CollisionContactGeomsPerTest > 80)
|
|
||||||
CollisionContactGeomsPerTest = 80;
|
|
||||||
|
|
||||||
d.GeomPlaneSetParams(Plane, req.Normal.X, req.Normal.Y, req.Normal.Z, req.length);
|
|
||||||
}
|
|
||||||
|
|
||||||
else
|
|
||||||
{
|
|
||||||
if (CollisionContactGeomsPerTest > 25)
|
|
||||||
CollisionContactGeomsPerTest = 25;
|
|
||||||
|
|
||||||
d.GeomRaySetLength(ray, req.length);
|
|
||||||
d.GeomRaySet(ray, req.Origin.X, req.Origin.Y, req.Origin.Z, req.Normal.X, req.Normal.Y, req.Normal.Z);
|
|
||||||
d.GeomRaySetParams(ray, 0, backfacecull);
|
|
||||||
d.GeomRaySetClosestHit(ray, closestHit);
|
|
||||||
|
|
||||||
if (req.callbackMethod is RaycastCallback)
|
|
||||||
{
|
|
||||||
// if we only want one get only one per Collision pair saving memory
|
|
||||||
CurrentRayFilter |= RayFilterFlags.ClosestHit;
|
|
||||||
d.GeomRaySetClosestHit(ray, 1);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
d.GeomRaySetClosestHit(ray, closestHit);
|
|
||||||
}
|
|
||||||
|
|
||||||
if ((CurrentRayFilter & RayFilterFlags.ContactsUnImportant) != 0)
|
|
||||||
unchecked
|
|
||||||
{
|
|
||||||
CollisionContactGeomsPerTest |= (int)d.CONTACTS_UNIMPORTANT;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (geom == IntPtr.Zero)
|
|
||||||
{
|
|
||||||
// translate ray filter to Collision flags
|
|
||||||
catflags = 0;
|
|
||||||
if ((CurrentRayFilter & RayFilterFlags.volumedtc) != 0)
|
|
||||||
catflags |= CollisionCategories.VolumeDtc;
|
|
||||||
if ((CurrentRayFilter & RayFilterFlags.phantom) != 0)
|
|
||||||
catflags |= CollisionCategories.Phantom;
|
|
||||||
if ((CurrentRayFilter & RayFilterFlags.agent) != 0)
|
|
||||||
catflags |= CollisionCategories.Character;
|
|
||||||
if ((CurrentRayFilter & RayFilterFlags.PrimsNonPhantom) != 0)
|
|
||||||
catflags |= CollisionCategories.Geom;
|
|
||||||
if ((CurrentRayFilter & RayFilterFlags.land) != 0)
|
|
||||||
catflags |= CollisionCategories.Land;
|
|
||||||
if ((CurrentRayFilter & RayFilterFlags.water) != 0)
|
|
||||||
catflags |= CollisionCategories.Water;
|
|
||||||
|
|
||||||
if (catflags != 0)
|
|
||||||
{
|
|
||||||
if (req.callbackMethod is ProbeBoxCallback)
|
|
||||||
{
|
|
||||||
catflags |= CollisionCategories.Space;
|
|
||||||
d.GeomSetCollideBits(Box, (uint)catflags);
|
|
||||||
d.GeomSetCategoryBits(Box, (uint)catflags);
|
|
||||||
doProbe(req, Box);
|
|
||||||
}
|
|
||||||
else if (req.callbackMethod is ProbeSphereCallback)
|
|
||||||
{
|
|
||||||
catflags |= CollisionCategories.Space;
|
|
||||||
d.GeomSetCollideBits(Sphere, (uint)catflags);
|
|
||||||
d.GeomSetCategoryBits(Sphere, (uint)catflags);
|
|
||||||
doProbe(req, Sphere);
|
|
||||||
}
|
|
||||||
else if (req.callbackMethod is ProbePlaneCallback)
|
|
||||||
{
|
|
||||||
catflags |= CollisionCategories.Space;
|
|
||||||
d.GeomSetCollideBits(Plane, (uint)catflags);
|
|
||||||
d.GeomSetCategoryBits(Plane, (uint)catflags);
|
|
||||||
doPlane(req,IntPtr.Zero);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
d.GeomSetCollideBits(ray, (uint)catflags);
|
|
||||||
doSpaceRay(req);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
// if we select a geom don't use filters
|
|
||||||
|
|
||||||
if (req.callbackMethod is ProbePlaneCallback)
|
|
||||||
{
|
|
||||||
d.GeomSetCollideBits(Plane, (uint)CollisionCategories.All);
|
|
||||||
doPlane(req,geom);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
d.GeomSetCollideBits(ray, (uint)CollisionCategories.All);
|
|
||||||
doGeomRay(req,geom);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (Util.EnvironmentTickCountSubtract(time) > MaxTimePerCallMS)
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
lock (m_contactResults)
|
|
||||||
m_contactResults.Clear();
|
|
||||||
|
|
||||||
return Util.EnvironmentTickCountSubtract(time);
|
|
||||||
}
|
|
||||||
/// <summary>
|
|
||||||
/// Method that actually initiates the raycast with spaces
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="req"></param>
|
|
||||||
///
|
|
||||||
|
|
||||||
private void NoContacts(ODERayRequest req)
|
|
||||||
{
|
|
||||||
if (req.callbackMethod is RaycastCallback)
|
|
||||||
{
|
|
||||||
((RaycastCallback)req.callbackMethod)(false, Vector3.Zero, 0, 0, Vector3.Zero);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
List<ContactResult> cresult = new List<ContactResult>();
|
|
||||||
|
|
||||||
if (req.callbackMethod is RayCallback)
|
|
||||||
((RayCallback)req.callbackMethod)(cresult);
|
|
||||||
else if (req.callbackMethod is ProbeBoxCallback)
|
|
||||||
((ProbeBoxCallback)req.callbackMethod)(cresult);
|
|
||||||
else if (req.callbackMethod is ProbeSphereCallback)
|
|
||||||
((ProbeSphereCallback)req.callbackMethod)(cresult);
|
|
||||||
}
|
|
||||||
|
|
||||||
private const RayFilterFlags FilterActiveSpace = RayFilterFlags.agent | RayFilterFlags.physical | RayFilterFlags.LSLPhantom;
|
|
||||||
// private const RayFilterFlags FilterStaticSpace = RayFilterFlags.water | RayFilterFlags.land | RayFilterFlags.nonphysical | RayFilterFlags.LSLPhanton;
|
|
||||||
private const RayFilterFlags FilterStaticSpace = RayFilterFlags.water | RayFilterFlags.nonphysical | RayFilterFlags.LSLPhantom;
|
|
||||||
|
|
||||||
private void doSpaceRay(ODERayRequest req)
|
|
||||||
{
|
|
||||||
// Collide tests
|
|
||||||
if ((CurrentRayFilter & FilterActiveSpace) != 0)
|
|
||||||
{
|
|
||||||
d.SpaceCollide2(ray, m_scene.ActiveSpace, IntPtr.Zero, nearCallback);
|
|
||||||
d.SpaceCollide2(ray, m_scene.CharsSpace, IntPtr.Zero, nearCallback);
|
|
||||||
}
|
|
||||||
if ((CurrentRayFilter & FilterStaticSpace) != 0 && (m_contactResults.Count < CurrentMaxCount))
|
|
||||||
d.SpaceCollide2(ray, m_scene.StaticSpace, IntPtr.Zero, nearCallback);
|
|
||||||
if ((CurrentRayFilter & RayFilterFlags.land) != 0 && (m_contactResults.Count < CurrentMaxCount))
|
|
||||||
{
|
|
||||||
// current ode land to ray collisions is very bad
|
|
||||||
// so for now limit its range badly
|
|
||||||
|
|
||||||
if (req.length > 30.0f)
|
|
||||||
d.GeomRaySetLength(ray, 30.0f);
|
|
||||||
|
|
||||||
d.SpaceCollide2(ray, m_scene.GroundSpace, IntPtr.Zero, nearCallback);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (req.callbackMethod is RaycastCallback)
|
|
||||||
{
|
|
||||||
// Define default results
|
|
||||||
bool hitYN = false;
|
|
||||||
uint hitConsumerID = 0;
|
|
||||||
float distance = float.MaxValue;
|
|
||||||
Vector3 closestcontact = Vector3.Zero;
|
|
||||||
Vector3 snormal = Vector3.Zero;
|
|
||||||
|
|
||||||
// Find closest contact and object.
|
|
||||||
lock (m_contactResults)
|
|
||||||
{
|
|
||||||
foreach (ContactResult cResult in m_contactResults)
|
|
||||||
{
|
|
||||||
if(cResult.Depth < distance)
|
|
||||||
{
|
|
||||||
closestcontact = cResult.Pos;
|
|
||||||
hitConsumerID = cResult.ConsumerID;
|
|
||||||
distance = cResult.Depth;
|
|
||||||
snormal = cResult.Normal;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
m_contactResults.Clear();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (distance > 0 && distance < float.MaxValue)
|
|
||||||
hitYN = true;
|
|
||||||
((RaycastCallback)req.callbackMethod)(hitYN, closestcontact, hitConsumerID, distance, snormal);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
List<ContactResult> cresult = new List<ContactResult>(m_contactResults.Count);
|
|
||||||
lock (m_PendingRequests)
|
|
||||||
{
|
|
||||||
cresult.AddRange(m_contactResults);
|
|
||||||
m_contactResults.Clear();
|
|
||||||
}
|
|
||||||
((RayCallback)req.callbackMethod)(cresult);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void doProbe(ODERayRequest req, IntPtr probe)
|
|
||||||
{
|
|
||||||
// Collide tests
|
|
||||||
if ((CurrentRayFilter & FilterActiveSpace) != 0)
|
|
||||||
{
|
|
||||||
d.SpaceCollide2(probe, m_scene.ActiveSpace, IntPtr.Zero, nearCallback);
|
|
||||||
d.SpaceCollide2(probe, m_scene.CharsSpace, IntPtr.Zero, nearCallback);
|
|
||||||
}
|
|
||||||
if ((CurrentRayFilter & FilterStaticSpace) != 0 && (m_contactResults.Count < CurrentMaxCount))
|
|
||||||
d.SpaceCollide2(probe, m_scene.StaticSpace, IntPtr.Zero, nearCallback);
|
|
||||||
if ((CurrentRayFilter & RayFilterFlags.land) != 0 && (m_contactResults.Count < CurrentMaxCount))
|
|
||||||
d.SpaceCollide2(probe, m_scene.GroundSpace, IntPtr.Zero, nearCallback);
|
|
||||||
|
|
||||||
List<ContactResult> cresult = new List<ContactResult>(m_contactResults.Count);
|
|
||||||
lock (m_PendingRequests)
|
|
||||||
{
|
|
||||||
cresult.AddRange(m_contactResults);
|
|
||||||
m_contactResults.Clear();
|
|
||||||
}
|
|
||||||
if (req.callbackMethod is ProbeBoxCallback)
|
|
||||||
((ProbeBoxCallback)req.callbackMethod)(cresult);
|
|
||||||
else if (req.callbackMethod is ProbeSphereCallback)
|
|
||||||
((ProbeSphereCallback)req.callbackMethod)(cresult);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void doPlane(ODERayRequest req,IntPtr geom)
|
|
||||||
{
|
|
||||||
// Collide tests
|
|
||||||
if (geom == IntPtr.Zero)
|
|
||||||
{
|
|
||||||
if ((CurrentRayFilter & FilterActiveSpace) != 0)
|
|
||||||
{
|
|
||||||
d.SpaceCollide2(Plane, m_scene.ActiveSpace, IntPtr.Zero, nearCallback);
|
|
||||||
d.SpaceCollide2(Plane, m_scene.CharsSpace, IntPtr.Zero, nearCallback);
|
|
||||||
}
|
|
||||||
if ((CurrentRayFilter & FilterStaticSpace) != 0 && (m_contactResults.Count < CurrentMaxCount))
|
|
||||||
d.SpaceCollide2(Plane, m_scene.StaticSpace, IntPtr.Zero, nearCallback);
|
|
||||||
if ((CurrentRayFilter & RayFilterFlags.land) != 0 && (m_contactResults.Count < CurrentMaxCount))
|
|
||||||
d.SpaceCollide2(Plane, m_scene.GroundSpace, IntPtr.Zero, nearCallback);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
d.SpaceCollide2(Plane, geom, IntPtr.Zero, nearCallback);
|
|
||||||
}
|
|
||||||
|
|
||||||
List<ContactResult> cresult = new List<ContactResult>(m_contactResults.Count);
|
|
||||||
lock (m_PendingRequests)
|
|
||||||
{
|
|
||||||
cresult.AddRange(m_contactResults);
|
|
||||||
m_contactResults.Clear();
|
|
||||||
}
|
|
||||||
|
|
||||||
((ProbePlaneCallback)req.callbackMethod)(cresult);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Method that actually initiates the raycast with a geom
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="req"></param>
|
|
||||||
private void doGeomRay(ODERayRequest req, IntPtr geom)
|
|
||||||
{
|
|
||||||
// Collide test
|
|
||||||
d.SpaceCollide2(ray, geom, IntPtr.Zero, nearCallback); // still do this to have full AABB pre test
|
|
||||||
|
|
||||||
if (req.callbackMethod is RaycastCallback)
|
|
||||||
{
|
|
||||||
// Define default results
|
|
||||||
bool hitYN = false;
|
|
||||||
uint hitConsumerID = 0;
|
|
||||||
float distance = float.MaxValue;
|
|
||||||
Vector3 closestcontact = Vector3.Zero;
|
|
||||||
Vector3 snormal = Vector3.Zero;
|
|
||||||
|
|
||||||
// Find closest contact and object.
|
|
||||||
lock (m_contactResults)
|
|
||||||
{
|
|
||||||
foreach (ContactResult cResult in m_contactResults)
|
|
||||||
{
|
|
||||||
if(cResult.Depth < distance )
|
|
||||||
{
|
|
||||||
closestcontact = cResult.Pos;
|
|
||||||
hitConsumerID = cResult.ConsumerID;
|
|
||||||
distance = cResult.Depth;
|
|
||||||
snormal = cResult.Normal;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
m_contactResults.Clear();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (distance > 0 && distance < float.MaxValue)
|
|
||||||
hitYN = true;
|
|
||||||
|
|
||||||
((RaycastCallback)req.callbackMethod)(hitYN, closestcontact, hitConsumerID, distance, snormal);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
List<ContactResult> cresult = new List<ContactResult>(m_contactResults.Count);
|
|
||||||
lock (m_PendingRequests)
|
|
||||||
{
|
|
||||||
cresult.AddRange(m_contactResults);
|
|
||||||
m_contactResults.Clear();
|
|
||||||
}
|
|
||||||
((RayCallback)req.callbackMethod)(cresult);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private bool GetCurContactGeom(int index, ref d.ContactGeom newcontactgeom)
|
|
||||||
{
|
|
||||||
IntPtr ContactgeomsArray = m_scene.ContactgeomsArray;
|
|
||||||
if (ContactgeomsArray == IntPtr.Zero || index >= CollisionContactGeomsPerTest)
|
|
||||||
return false;
|
|
||||||
|
|
||||||
IntPtr contactptr = new IntPtr(ContactgeomsArray.ToInt64() + (Int64)(index * d.ContactGeom.unmanagedSizeOf));
|
|
||||||
newcontactgeom = (d.ContactGeom)Marshal.PtrToStructure(contactptr, typeof(d.ContactGeom));
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
// This is the standard Near. g1 is the ray
|
|
||||||
private void near(IntPtr space, IntPtr g1, IntPtr g2)
|
|
||||||
{
|
|
||||||
if (g2 == IntPtr.Zero || g1 == g2)
|
|
||||||
return;
|
|
||||||
|
|
||||||
if (m_contactResults.Count >= CurrentMaxCount)
|
|
||||||
return;
|
|
||||||
|
|
||||||
if (d.GeomIsSpace(g2))
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
d.SpaceCollide2(g1, g2, IntPtr.Zero, nearCallback);
|
|
||||||
}
|
|
||||||
catch (Exception e)
|
|
||||||
{
|
|
||||||
m_log.WarnFormat("[PHYSICS Ray]: Unable to Space collide test an object: {0}", e.Message);
|
|
||||||
}
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
int count = 0;
|
|
||||||
try
|
|
||||||
{
|
|
||||||
count = d.CollidePtr(g1, g2, CollisionContactGeomsPerTest, m_scene.ContactgeomsArray, d.ContactGeom.unmanagedSizeOf);
|
|
||||||
}
|
|
||||||
catch (Exception e)
|
|
||||||
{
|
|
||||||
m_log.WarnFormat("[PHYSICS Ray]: Unable to collide test an object: {0}", e.Message);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (count == 0)
|
|
||||||
return;
|
|
||||||
/*
|
|
||||||
uint cat1 = d.GeomGetCategoryBits(g1);
|
|
||||||
uint cat2 = d.GeomGetCategoryBits(g2);
|
|
||||||
uint col1 = d.GeomGetCollideBits(g1);
|
|
||||||
uint col2 = d.GeomGetCollideBits(g2);
|
|
||||||
*/
|
|
||||||
|
|
||||||
uint ID = 0;
|
|
||||||
PhysicsActor p2 = null;
|
|
||||||
|
|
||||||
m_scene.actor_name_map.TryGetValue(g2, out p2);
|
|
||||||
|
|
||||||
if (p2 == null)
|
|
||||||
return;
|
|
||||||
|
|
||||||
switch (p2.PhysicsActorType)
|
|
||||||
{
|
|
||||||
case (int)ActorTypes.Prim:
|
|
||||||
|
|
||||||
RayFilterFlags thisFlags;
|
|
||||||
|
|
||||||
if (p2.IsPhysical)
|
|
||||||
thisFlags = RayFilterFlags.physical;
|
|
||||||
else
|
|
||||||
thisFlags = RayFilterFlags.nonphysical;
|
|
||||||
|
|
||||||
if (p2.Phantom)
|
|
||||||
thisFlags |= RayFilterFlags.phantom;
|
|
||||||
|
|
||||||
if (p2.IsVolumeDtc)
|
|
||||||
thisFlags |= RayFilterFlags.volumedtc;
|
|
||||||
|
|
||||||
if ((thisFlags & CurrentRayFilter) == 0)
|
|
||||||
return;
|
|
||||||
|
|
||||||
ID = ((OdePrim)p2).LocalID;
|
|
||||||
break;
|
|
||||||
|
|
||||||
case (int)ActorTypes.Agent:
|
|
||||||
|
|
||||||
if ((CurrentRayFilter & RayFilterFlags.agent) == 0)
|
|
||||||
return;
|
|
||||||
else
|
|
||||||
ID = ((OdeCharacter)p2).LocalID;
|
|
||||||
break;
|
|
||||||
|
|
||||||
case (int)ActorTypes.Ground:
|
|
||||||
|
|
||||||
if ((CurrentRayFilter & RayFilterFlags.land) == 0)
|
|
||||||
return;
|
|
||||||
break;
|
|
||||||
|
|
||||||
case (int)ActorTypes.Water:
|
|
||||||
|
|
||||||
if ((CurrentRayFilter & RayFilterFlags.water) == 0)
|
|
||||||
return;
|
|
||||||
break;
|
|
||||||
|
|
||||||
default:
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
d.ContactGeom curcontact = new d.ContactGeom();
|
|
||||||
|
|
||||||
// closestHit for now only works for meshs, so must do it for others
|
|
||||||
if ((CurrentRayFilter & RayFilterFlags.ClosestHit) == 0)
|
|
||||||
{
|
|
||||||
// Loop all contacts, build results.
|
|
||||||
for (int i = 0; i < count; i++)
|
|
||||||
{
|
|
||||||
if (!GetCurContactGeom(i, ref curcontact))
|
|
||||||
break;
|
|
||||||
|
|
||||||
ContactResult collisionresult = new ContactResult();
|
|
||||||
collisionresult.ConsumerID = ID;
|
|
||||||
collisionresult.Pos.X = curcontact.pos.X;
|
|
||||||
collisionresult.Pos.Y = curcontact.pos.Y;
|
|
||||||
collisionresult.Pos.Z = curcontact.pos.Z;
|
|
||||||
collisionresult.Depth = curcontact.depth;
|
|
||||||
collisionresult.Normal.X = curcontact.normal.X;
|
|
||||||
collisionresult.Normal.Y = curcontact.normal.Y;
|
|
||||||
collisionresult.Normal.Z = curcontact.normal.Z;
|
|
||||||
lock (m_contactResults)
|
|
||||||
{
|
|
||||||
m_contactResults.Add(collisionresult);
|
|
||||||
if (m_contactResults.Count >= CurrentMaxCount)
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
// keep only closest contact
|
|
||||||
ContactResult collisionresult = new ContactResult();
|
|
||||||
collisionresult.ConsumerID = ID;
|
|
||||||
collisionresult.Depth = float.MaxValue;
|
|
||||||
|
|
||||||
for (int i = 0; i < count; i++)
|
|
||||||
{
|
|
||||||
if (!GetCurContactGeom(i, ref curcontact))
|
|
||||||
break;
|
|
||||||
|
|
||||||
if (curcontact.depth < collisionresult.Depth)
|
|
||||||
{
|
|
||||||
collisionresult.Pos.X = curcontact.pos.X;
|
|
||||||
collisionresult.Pos.Y = curcontact.pos.Y;
|
|
||||||
collisionresult.Pos.Z = curcontact.pos.Z;
|
|
||||||
collisionresult.Depth = curcontact.depth;
|
|
||||||
collisionresult.Normal.X = curcontact.normal.X;
|
|
||||||
collisionresult.Normal.Y = curcontact.normal.Y;
|
|
||||||
collisionresult.Normal.Z = curcontact.normal.Z;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (collisionresult.Depth != float.MaxValue)
|
|
||||||
{
|
|
||||||
lock (m_contactResults)
|
|
||||||
m_contactResults.Add(collisionresult);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Dereference the creator scene so that it can be garbage collected if needed.
|
|
||||||
/// </summary>
|
|
||||||
internal void Dispose()
|
|
||||||
{
|
|
||||||
m_scene = null;
|
|
||||||
if (ray != IntPtr.Zero)
|
|
||||||
{
|
|
||||||
d.GeomDestroy(ray);
|
|
||||||
ray = IntPtr.Zero;
|
|
||||||
}
|
|
||||||
if (Box != IntPtr.Zero)
|
|
||||||
{
|
|
||||||
d.GeomDestroy(Box);
|
|
||||||
Box = IntPtr.Zero;
|
|
||||||
}
|
|
||||||
if (Sphere != IntPtr.Zero)
|
|
||||||
{
|
|
||||||
d.GeomDestroy(Sphere);
|
|
||||||
Sphere = IntPtr.Zero;
|
|
||||||
}
|
|
||||||
if (Plane != IntPtr.Zero)
|
|
||||||
{
|
|
||||||
d.GeomDestroy(Plane);
|
|
||||||
Plane = IntPtr.Zero;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public struct ODERayRequest
|
|
||||||
{
|
|
||||||
public PhysicsActor actor;
|
|
||||||
public Vector3 Origin;
|
|
||||||
public Vector3 Normal;
|
|
||||||
public int Count;
|
|
||||||
public float length;
|
|
||||||
public object callbackMethod;
|
|
||||||
public RayFilterFlags filter;
|
|
||||||
public Quaternion orientation;
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,356 +0,0 @@
|
||||||
/*
|
|
||||||
* Copyright (c) Contributors, http://opensimulator.org/
|
|
||||||
* See CONTRIBUTORS.TXT for a full list of copyright holders.
|
|
||||||
*
|
|
||||||
* Redistribution and use in source and binary forms, with or without
|
|
||||||
* modification, are permitted provided that the following conditions are met:
|
|
||||||
* * Redistributions of source code must retain the above copyright
|
|
||||||
* notice, this list of conditions and the following disclaimer.
|
|
||||||
* * Redistributions in binary form must reproduce the above copyright
|
|
||||||
* notice, this list of conditions and the following disclaimer in the
|
|
||||||
* documentation and/or other materials provided with the distribution.
|
|
||||||
* * Neither the name of the OpenSimulator Project nor the
|
|
||||||
* names of its contributors may be used to endorse or promote products
|
|
||||||
* derived from this software without specific prior written permission.
|
|
||||||
*
|
|
||||||
* THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
|
|
||||||
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
|
||||||
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
|
||||||
* DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
|
|
||||||
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
|
||||||
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
|
||||||
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
|
||||||
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
|
||||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
|
||||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
||||||
*/
|
|
||||||
// Ubit 2012
|
|
||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Reflection;
|
|
||||||
using System.Runtime.InteropServices;
|
|
||||||
using System.Text;
|
|
||||||
using OpenSim.Framework;
|
|
||||||
using OpenSim.Region.PhysicsModules.SharedBase;
|
|
||||||
using OdeAPI;
|
|
||||||
using log4net;
|
|
||||||
using OpenMetaverse;
|
|
||||||
|
|
||||||
namespace OpenSim.Region.PhysicsModules.OdePlugin
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// </summary>
|
|
||||||
public class ODESitAvatar
|
|
||||||
{
|
|
||||||
private OdeScene m_scene;
|
|
||||||
private ODERayCastRequestManager m_raymanager;
|
|
||||||
|
|
||||||
public ODESitAvatar(OdeScene pScene, ODERayCastRequestManager raymanager)
|
|
||||||
{
|
|
||||||
m_scene = pScene;
|
|
||||||
m_raymanager = raymanager;
|
|
||||||
}
|
|
||||||
|
|
||||||
private static Vector3 SitAjust = new Vector3(0, 0, 0.4f);
|
|
||||||
private const RayFilterFlags RaySitFlags = RayFilterFlags.AllPrims | RayFilterFlags.ClosestHit;
|
|
||||||
|
|
||||||
private void RotAroundZ(float x, float y, ref Quaternion ori)
|
|
||||||
{
|
|
||||||
double ang = Math.Atan2(y, x);
|
|
||||||
ang *= 0.5d;
|
|
||||||
float s = (float)Math.Sin(ang);
|
|
||||||
float c = (float)Math.Cos(ang);
|
|
||||||
|
|
||||||
ori.X = 0;
|
|
||||||
ori.Y = 0;
|
|
||||||
ori.Z = s;
|
|
||||||
ori.W = c;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
public void Sit(PhysicsActor actor, Vector3 avPos, Vector3 avCameraPosition, Vector3 offset, Vector3 avOffset, SitAvatarCallback PhysicsSitResponse)
|
|
||||||
{
|
|
||||||
if (!m_scene.haveActor(actor) || !(actor is OdePrim) || ((OdePrim)actor).prim_geom == IntPtr.Zero)
|
|
||||||
{
|
|
||||||
PhysicsSitResponse(-1, actor.LocalID, offset, Quaternion.Identity);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
IntPtr geom = ((OdePrim)actor).prim_geom;
|
|
||||||
|
|
||||||
Vector3 geopos = d.GeomGetPositionOMV(geom);
|
|
||||||
Quaternion geomOri = d.GeomGetQuaternionOMV(geom);
|
|
||||||
|
|
||||||
// Vector3 geopos = actor.Position;
|
|
||||||
// Quaternion geomOri = actor.Orientation;
|
|
||||||
|
|
||||||
Quaternion geomInvOri = Quaternion.Conjugate(geomOri);
|
|
||||||
|
|
||||||
Quaternion ori = Quaternion.Identity;
|
|
||||||
|
|
||||||
Vector3 rayDir = geopos + offset - avCameraPosition;
|
|
||||||
|
|
||||||
float raylen = rayDir.Length();
|
|
||||||
if (raylen < 0.001f)
|
|
||||||
{
|
|
||||||
PhysicsSitResponse(-1, actor.LocalID, offset, Quaternion.Identity);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
float t = 1 / raylen;
|
|
||||||
rayDir.X *= t;
|
|
||||||
rayDir.Y *= t;
|
|
||||||
rayDir.Z *= t;
|
|
||||||
|
|
||||||
raylen += 30f; // focal point may be far
|
|
||||||
List<ContactResult> rayResults;
|
|
||||||
|
|
||||||
rayResults = m_scene.RaycastActor(actor, avCameraPosition, rayDir, raylen, 1, RaySitFlags);
|
|
||||||
if (rayResults.Count == 0)
|
|
||||||
{
|
|
||||||
/* if this fundamental ray failed, then just fail so user can try another spot and not be sitted far on a big prim
|
|
||||||
d.AABB aabb;
|
|
||||||
d.GeomGetAABB(geom, out aabb);
|
|
||||||
offset = new Vector3(avOffset.X, 0, aabb.MaxZ + avOffset.Z - geopos.Z);
|
|
||||||
ori = geomInvOri;
|
|
||||||
offset *= geomInvOri;
|
|
||||||
PhysicsSitResponse(1, actor.LocalID, offset, ori);
|
|
||||||
*/
|
|
||||||
PhysicsSitResponse(0, actor.LocalID, offset, ori);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
int status = 1;
|
|
||||||
|
|
||||||
offset = rayResults[0].Pos - geopos;
|
|
||||||
|
|
||||||
d.GeomClassID geoclass = d.GeomGetClass(geom);
|
|
||||||
|
|
||||||
if (geoclass == d.GeomClassID.SphereClass)
|
|
||||||
{
|
|
||||||
float r = d.GeomSphereGetRadius(geom);
|
|
||||||
|
|
||||||
offset.Normalize();
|
|
||||||
offset *= r;
|
|
||||||
|
|
||||||
RotAroundZ(offset.X, offset.Y, ref ori);
|
|
||||||
|
|
||||||
if (r < 0.4f)
|
|
||||||
{
|
|
||||||
offset = new Vector3(0, 0, r);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
if (offset.Z < 0.4f)
|
|
||||||
{
|
|
||||||
t = offset.Z;
|
|
||||||
float rsq = r * r;
|
|
||||||
|
|
||||||
t = 1.0f / (rsq - t * t);
|
|
||||||
offset.X *= t;
|
|
||||||
offset.Y *= t;
|
|
||||||
offset.Z = 0.4f;
|
|
||||||
t = rsq - 0.16f;
|
|
||||||
offset.X *= t;
|
|
||||||
offset.Y *= t;
|
|
||||||
}
|
|
||||||
else if (r > 0.8f && offset.Z > 0.8f * r)
|
|
||||||
{
|
|
||||||
status = 3;
|
|
||||||
avOffset.X = -avOffset.X;
|
|
||||||
avOffset.Z *= 1.6f;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
offset += avOffset * ori;
|
|
||||||
|
|
||||||
ori = geomInvOri * ori;
|
|
||||||
offset *= geomInvOri;
|
|
||||||
|
|
||||||
PhysicsSitResponse(status, actor.LocalID, offset, ori);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
Vector3 norm = rayResults[0].Normal;
|
|
||||||
|
|
||||||
if (norm.Z < -0.4f)
|
|
||||||
{
|
|
||||||
PhysicsSitResponse(0, actor.LocalID, offset, Quaternion.Identity);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
float SitNormX = -rayDir.X;
|
|
||||||
float SitNormY = -rayDir.Y;
|
|
||||||
|
|
||||||
Vector3 pivot = geopos + offset;
|
|
||||||
|
|
||||||
float edgeNormalX = norm.X;
|
|
||||||
float edgeNormalY = norm.Y;
|
|
||||||
float edgeDirX = -rayDir.X;
|
|
||||||
float edgeDirY = -rayDir.Y;
|
|
||||||
Vector3 edgePos = rayResults[0].Pos;
|
|
||||||
float edgeDist = float.MaxValue;
|
|
||||||
|
|
||||||
bool foundEdge = false;
|
|
||||||
|
|
||||||
if (norm.Z < 0.5f)
|
|
||||||
{
|
|
||||||
float rayDist = 4.0f;
|
|
||||||
|
|
||||||
for (int i = 0; i < 6; i++)
|
|
||||||
{
|
|
||||||
pivot.X -= 0.01f * norm.X;
|
|
||||||
pivot.Y -= 0.01f * norm.Y;
|
|
||||||
pivot.Z -= 0.01f * norm.Z;
|
|
||||||
|
|
||||||
rayDir.X = -norm.X * norm.Z;
|
|
||||||
rayDir.Y = -norm.Y * norm.Z;
|
|
||||||
rayDir.Z = 1.0f - norm.Z * norm.Z;
|
|
||||||
rayDir.Normalize();
|
|
||||||
|
|
||||||
rayResults = m_scene.RaycastActor(actor, pivot, rayDir, rayDist, 1, RayFilterFlags.AllPrims);
|
|
||||||
if (rayResults.Count == 0)
|
|
||||||
break;
|
|
||||||
|
|
||||||
if (Math.Abs(rayResults[0].Normal.Z) < 0.7f)
|
|
||||||
{
|
|
||||||
rayDist -= rayResults[0].Depth;
|
|
||||||
if (rayDist < 0f)
|
|
||||||
break;
|
|
||||||
|
|
||||||
pivot = rayResults[0].Pos;
|
|
||||||
norm = rayResults[0].Normal;
|
|
||||||
edgeNormalX = norm.X;
|
|
||||||
edgeNormalY = norm.Y;
|
|
||||||
edgeDirX = -rayDir.X;
|
|
||||||
edgeDirY = -rayDir.Y;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
foundEdge = true;
|
|
||||||
edgePos = rayResults[0].Pos;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!foundEdge)
|
|
||||||
{
|
|
||||||
PhysicsSitResponse(0, actor.LocalID, offset, ori);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
avOffset.X *= 0.5f;
|
|
||||||
}
|
|
||||||
|
|
||||||
else if (norm.Z > 0.866f)
|
|
||||||
{
|
|
||||||
float toCamBaseX = avCameraPosition.X - pivot.X;
|
|
||||||
float toCamBaseY = avCameraPosition.Y - pivot.Y;
|
|
||||||
float toCamX = toCamBaseX;
|
|
||||||
float toCamY = toCamBaseY;
|
|
||||||
|
|
||||||
for (int j = 0; j < 4; j++)
|
|
||||||
{
|
|
||||||
float rayDist = 1.0f;
|
|
||||||
float curEdgeDist = 0.0f;
|
|
||||||
|
|
||||||
for (int i = 0; i < 3; i++)
|
|
||||||
{
|
|
||||||
pivot.Z -= 0.01f;
|
|
||||||
rayDir.X = toCamX;
|
|
||||||
rayDir.Y = toCamY;
|
|
||||||
rayDir.Z = (-toCamX * norm.X - toCamY * norm.Y) / norm.Z;
|
|
||||||
rayDir.Normalize();
|
|
||||||
|
|
||||||
rayResults = m_scene.RaycastActor(actor, pivot, rayDir, rayDist, 1, RayFilterFlags.AllPrims);
|
|
||||||
if (rayResults.Count == 0)
|
|
||||||
break;
|
|
||||||
|
|
||||||
curEdgeDist += rayResults[0].Depth;
|
|
||||||
|
|
||||||
if (rayResults[0].Normal.Z > 0.5f)
|
|
||||||
{
|
|
||||||
rayDist -= rayResults[0].Depth;
|
|
||||||
if (rayDist < 0f)
|
|
||||||
break;
|
|
||||||
|
|
||||||
pivot = rayResults[0].Pos;
|
|
||||||
norm = rayResults[0].Normal;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
foundEdge = true;
|
|
||||||
if (curEdgeDist < edgeDist)
|
|
||||||
{
|
|
||||||
edgeDist = curEdgeDist;
|
|
||||||
edgeNormalX = rayResults[0].Normal.X;
|
|
||||||
edgeNormalY = rayResults[0].Normal.Y;
|
|
||||||
edgeDirX = rayDir.X;
|
|
||||||
edgeDirY = rayDir.Y;
|
|
||||||
edgePos = rayResults[0].Pos;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (foundEdge && edgeDist < 0.2f)
|
|
||||||
break;
|
|
||||||
|
|
||||||
pivot = geopos + offset;
|
|
||||||
|
|
||||||
switch (j)
|
|
||||||
{
|
|
||||||
case 0:
|
|
||||||
toCamX = -toCamBaseY;
|
|
||||||
toCamY = toCamBaseX;
|
|
||||||
break;
|
|
||||||
case 1:
|
|
||||||
toCamX = toCamBaseY;
|
|
||||||
toCamY = -toCamBaseX;
|
|
||||||
break;
|
|
||||||
case 2:
|
|
||||||
toCamX = -toCamBaseX;
|
|
||||||
toCamY = -toCamBaseY;
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!foundEdge)
|
|
||||||
{
|
|
||||||
avOffset.X = -avOffset.X;
|
|
||||||
avOffset.Z *= 1.6f;
|
|
||||||
|
|
||||||
RotAroundZ(SitNormX, SitNormY, ref ori);
|
|
||||||
|
|
||||||
offset += avOffset * ori;
|
|
||||||
|
|
||||||
ori = geomInvOri * ori;
|
|
||||||
offset *= geomInvOri;
|
|
||||||
|
|
||||||
PhysicsSitResponse(3, actor.LocalID, offset, ori);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
avOffset.X *= 0.5f;
|
|
||||||
}
|
|
||||||
|
|
||||||
SitNormX = edgeNormalX;
|
|
||||||
SitNormY = edgeNormalY;
|
|
||||||
if (edgeDirX * SitNormX + edgeDirY * SitNormY < 0)
|
|
||||||
{
|
|
||||||
SitNormX = -SitNormX;
|
|
||||||
SitNormY = -SitNormY;
|
|
||||||
}
|
|
||||||
|
|
||||||
RotAroundZ(SitNormX, SitNormY, ref ori);
|
|
||||||
|
|
||||||
offset = edgePos + avOffset * ori;
|
|
||||||
offset -= geopos;
|
|
||||||
|
|
||||||
ori = geomInvOri * ori;
|
|
||||||
offset *= geomInvOri;
|
|
||||||
|
|
||||||
PhysicsSitResponse(1, actor.LocalID, offset, ori);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
|
@ -359,7 +359,7 @@
|
||||||
</Files>
|
</Files>
|
||||||
</Project>
|
</Project>
|
||||||
|
|
||||||
<Project frameworkVersion="v4_0" name="OpenSim.Region.PhysicsModules.UbitOdePlugin" path="OpenSim/Region/PhysicsModules/UbitOdePlugin" type="Library">
|
<Project frameworkVersion="v4_0" name="OpenSim.Region.PhysicsModules.UbitOde" path="OpenSim/Region/PhysicsModules/UbitOde" type="Library">
|
||||||
<Configuration name="Debug">
|
<Configuration name="Debug">
|
||||||
<Options>
|
<Options>
|
||||||
<OutputPath>../../../../bin/Physics/</OutputPath>
|
<OutputPath>../../../../bin/Physics/</OutputPath>
|
||||||
|
|
Loading…
Reference in New Issue