More 'everything is a module' merging.

Have most of UbitOde converted.
There are compile errors in OpenSimBase as the new modules stuff is not all there.
Removed ChOdePlugin as it's connection to OdePlugin was tangled.
This commit is contained in:
Robert Adams
2015-09-08 06:15:46 -07:00
parent e5367d822b
commit 4dd17c4117
28 changed files with 102 additions and 10702 deletions

View File

@@ -671,7 +671,7 @@ namespace OpenSim.Region.PhysicsModule.ODE
}
#endif
public override void Initialise(IMesher meshmerizer, IConfigSource config, Vector3 regionExtent)
public void Initialise(IMesher meshmerizer, IConfigSource config, Vector3 regionExtent)
{
WorldExtents.X = regionExtent.X;
m_regionWidth = (uint)regionExtent.X;
@@ -682,7 +682,7 @@ namespace OpenSim.Region.PhysicsModule.ODE
}
// Initialize the mesh plugin
public override void Initialise(IMesher meshmerizer, IConfigSource config)
public void Initialise(IMesher meshmerizer, IConfigSource config)
{
InitializeExtraStats();

View File

@@ -0,0 +1,340 @@
/*
* 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.Physics.Manager;
using OpenSim.Region.Physics.Meshing;
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;
}
}

View File

@@ -0,0 +1,601 @@
/*
* 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.IO;
using System.Runtime.InteropServices;
using OpenSim.Region.Physics.Manager;
using PrimMesher;
using OpenMetaverse;
using System.Runtime.Serialization;
using System.Runtime.Serialization.Formatters.Binary;
namespace OpenSim.Region.Physics.Meshing
{
public class MeshBuildingData
{
public Dictionary<Vertex, int> m_vertices;
public List<Triangle> m_triangles;
public float m_obbXmin;
public float m_obbXmax;
public float m_obbYmin;
public float m_obbYmax;
public float m_obbZmin;
public float m_obbZmax;
public Vector3 m_centroid;
public int m_centroidDiv;
}
[Serializable()]
public class Mesh : IMesh
{
float[] vertices;
int[] indexes;
Vector3 m_obb;
Vector3 m_obboffset;
[NonSerialized()]
MeshBuildingData m_bdata;
[NonSerialized()]
GCHandle vhandler;
[NonSerialized()]
GCHandle ihandler;
[NonSerialized()]
IntPtr m_verticesPtr = IntPtr.Zero;
[NonSerialized()]
IntPtr m_indicesPtr = IntPtr.Zero;
[NonSerialized()]
int m_vertexCount = 0;
[NonSerialized()]
int m_indexCount = 0;
public int RefCount { get; set; }
public AMeshKey Key { get; set; }
private class vertexcomp : IEqualityComparer<Vertex>
{
public bool Equals(Vertex v1, Vertex v2)
{
if (v1.X == v2.X && v1.Y == v2.Y && v1.Z == v2.Z)
return true;
else
return false;
}
public int GetHashCode(Vertex v)
{
int a = v.X.GetHashCode();
int b = v.Y.GetHashCode();
int c = v.Z.GetHashCode();
return (a << 16) ^ (b << 8) ^ c;
}
}
public Mesh()
{
vertexcomp vcomp = new vertexcomp();
m_bdata = new MeshBuildingData();
m_bdata.m_vertices = new Dictionary<Vertex, int>(vcomp);
m_bdata.m_triangles = new List<Triangle>();
m_bdata.m_centroid = Vector3.Zero;
m_bdata.m_centroidDiv = 0;
m_bdata.m_obbXmin = float.MaxValue;
m_bdata.m_obbXmax = float.MinValue;
m_bdata.m_obbYmin = float.MaxValue;
m_bdata.m_obbYmax = float.MinValue;
m_bdata.m_obbZmin = float.MaxValue;
m_bdata.m_obbZmax = float.MinValue;
m_obb = new Vector3(0.5f, 0.5f, 0.5f);
m_obboffset = Vector3.Zero;
}
public Mesh Scale(Vector3 scale)
{
if (m_verticesPtr == null || m_indicesPtr == null)
return null;
Mesh result = new Mesh();
float x = scale.X;
float y = scale.Y;
float z = scale.Z;
result.m_obb.X = m_obb.X * x;
result.m_obb.Y = m_obb.Y * y;
result.m_obb.Z = m_obb.Z * z;
result.m_obboffset.X = m_obboffset.X * x;
result.m_obboffset.Y = m_obboffset.Y * y;
result.m_obboffset.Z = m_obboffset.Z * z;
result.vertices = new float[vertices.Length];
int j = 0;
for (int i = 0; i < m_vertexCount; i++)
{
result.vertices[j] = vertices[j] * x;
j++;
result.vertices[j] = vertices[j] * y;
j++;
result.vertices[j] = vertices[j] * z;
j++;
}
result.indexes = new int[indexes.Length];
indexes.CopyTo(result.indexes,0);
result.pinMemory();
return result;
}
public Mesh Clone()
{
Mesh result = new Mesh();
if (m_bdata != null)
{
result.m_bdata = new MeshBuildingData();
foreach (Triangle t in m_bdata.m_triangles)
{
result.Add(new Triangle(t.v1.Clone(), t.v2.Clone(), t.v3.Clone()));
}
result.m_bdata.m_centroid = m_bdata.m_centroid;
result.m_bdata.m_centroidDiv = m_bdata.m_centroidDiv;
result.m_bdata.m_obbXmin = m_bdata.m_obbXmin;
result.m_bdata.m_obbXmax = m_bdata.m_obbXmax;
result.m_bdata.m_obbYmin = m_bdata.m_obbYmin;
result.m_bdata.m_obbYmax = m_bdata.m_obbYmax;
result.m_bdata.m_obbZmin = m_bdata.m_obbZmin;
result.m_bdata.m_obbZmax = m_bdata.m_obbZmax;
}
result.m_obb = m_obb;
result.m_obboffset = m_obboffset;
return result;
}
public void addVertexLStats(Vertex v)
{
float x = v.X;
float y = v.Y;
float z = v.Z;
m_bdata.m_centroid.X += x;
m_bdata.m_centroid.Y += y;
m_bdata.m_centroid.Z += z;
m_bdata.m_centroidDiv++;
if (x > m_bdata.m_obbXmax)
m_bdata.m_obbXmax = x;
else if (x < m_bdata.m_obbXmin)
m_bdata.m_obbXmin = x;
if (y > m_bdata.m_obbYmax)
m_bdata.m_obbYmax = y;
else if (y < m_bdata.m_obbYmin)
m_bdata.m_obbYmin = y;
if (z > m_bdata.m_obbZmax)
m_bdata.m_obbZmax = z;
else if (z < m_bdata.m_obbZmin)
m_bdata.m_obbZmin = z;
}
public void Add(Triangle triangle)
{
if (m_indicesPtr != IntPtr.Zero || m_verticesPtr != IntPtr.Zero)
throw new NotSupportedException("Attempt to Add to a pinned Mesh");
triangle.v1.X = (float)Math.Round(triangle.v1.X, 6);
triangle.v1.Y = (float)Math.Round(triangle.v1.Y, 6);
triangle.v1.Z = (float)Math.Round(triangle.v1.Z, 6);
triangle.v2.X = (float)Math.Round(triangle.v2.X, 6);
triangle.v2.Y = (float)Math.Round(triangle.v2.Y, 6);
triangle.v2.Z = (float)Math.Round(triangle.v2.Z, 6);
triangle.v3.X = (float)Math.Round(triangle.v3.X, 6);
triangle.v3.Y = (float)Math.Round(triangle.v3.Y, 6);
triangle.v3.Z = (float)Math.Round(triangle.v3.Z, 6);
if ((triangle.v1.X == triangle.v2.X && triangle.v1.Y == triangle.v2.Y && triangle.v1.Z == triangle.v2.Z)
|| (triangle.v1.X == triangle.v3.X && triangle.v1.Y == triangle.v3.Y && triangle.v1.Z == triangle.v3.Z)
|| (triangle.v2.X == triangle.v3.X && triangle.v2.Y == triangle.v3.Y && triangle.v2.Z == triangle.v3.Z)
)
{
return;
}
if (m_bdata.m_vertices.Count == 0)
{
m_bdata.m_centroidDiv = 0;
m_bdata.m_centroid = Vector3.Zero;
}
if (!m_bdata.m_vertices.ContainsKey(triangle.v1))
{
m_bdata.m_vertices[triangle.v1] = m_bdata.m_vertices.Count;
addVertexLStats(triangle.v1);
}
if (!m_bdata.m_vertices.ContainsKey(triangle.v2))
{
m_bdata.m_vertices[triangle.v2] = m_bdata.m_vertices.Count;
addVertexLStats(triangle.v2);
}
if (!m_bdata.m_vertices.ContainsKey(triangle.v3))
{
m_bdata.m_vertices[triangle.v3] = m_bdata.m_vertices.Count;
addVertexLStats(triangle.v3);
}
m_bdata.m_triangles.Add(triangle);
}
public Vector3 GetCentroid()
{
return m_obboffset;
}
public Vector3 GetOBB()
{
return m_obb;
float x, y, z;
if (m_bdata.m_centroidDiv > 0)
{
x = (m_bdata.m_obbXmax - m_bdata.m_obbXmin) * 0.5f;
y = (m_bdata.m_obbYmax - m_bdata.m_obbYmin) * 0.5f;
z = (m_bdata.m_obbZmax - m_bdata.m_obbZmin) * 0.5f;
}
else // ??
{
x = 0.5f;
y = 0.5f;
z = 0.5f;
}
return new Vector3(x, y, z);
}
public List<Vector3> getVertexList()
{
List<Vector3> result = new List<Vector3>();
foreach (Vertex v in m_bdata.m_vertices.Keys)
{
result.Add(new Vector3(v.X, v.Y, v.Z));
}
return result;
}
public float[] getVertexListAsFloat()
{
if (m_bdata.m_vertices == null)
throw new NotSupportedException();
float[] result = new float[m_bdata.m_vertices.Count * 3];
foreach (KeyValuePair<Vertex, int> kvp in m_bdata.m_vertices)
{
Vertex v = kvp.Key;
int i = kvp.Value;
result[3 * i + 0] = v.X;
result[3 * i + 1] = v.Y;
result[3 * i + 2] = v.Z;
}
return result;
}
public float[] getVertexListAsFloatLocked()
{
return null;
}
public void getVertexListAsPtrToFloatArray(out IntPtr _vertices, out int vertexStride, out int vertexCount)
{
// A vertex is 3 floats
vertexStride = 3 * sizeof(float);
// If there isn't an unmanaged array allocated yet, do it now
if (m_verticesPtr == IntPtr.Zero && m_bdata != null)
{
vertices = getVertexListAsFloat();
// Each vertex is 3 elements (floats)
m_vertexCount = vertices.Length / 3;
vhandler = GCHandle.Alloc(vertices, GCHandleType.Pinned);
m_verticesPtr = vhandler.AddrOfPinnedObject();
GC.AddMemoryPressure(Buffer.ByteLength(vertices));
}
_vertices = m_verticesPtr;
vertexCount = m_vertexCount;
}
public int[] getIndexListAsInt()
{
if (m_bdata.m_triangles == null)
throw new NotSupportedException();
int[] result = new int[m_bdata.m_triangles.Count * 3];
for (int i = 0; i < m_bdata.m_triangles.Count; i++)
{
Triangle t = m_bdata.m_triangles[i];
result[3 * i + 0] = m_bdata.m_vertices[t.v1];
result[3 * i + 1] = m_bdata.m_vertices[t.v2];
result[3 * i + 2] = m_bdata.m_vertices[t.v3];
}
return result;
}
/// <summary>
/// creates a list of index values that defines triangle faces. THIS METHOD FREES ALL NON-PINNED MESH DATA
/// </summary>
/// <returns></returns>
public int[] getIndexListAsIntLocked()
{
return null;
}
public void getIndexListAsPtrToIntArray(out IntPtr indices, out int triStride, out int indexCount)
{
// If there isn't an unmanaged array allocated yet, do it now
if (m_indicesPtr == IntPtr.Zero && m_bdata != null)
{
indexes = getIndexListAsInt();
m_indexCount = indexes.Length;
ihandler = GCHandle.Alloc(indexes, GCHandleType.Pinned);
m_indicesPtr = ihandler.AddrOfPinnedObject();
GC.AddMemoryPressure(Buffer.ByteLength(indexes));
}
// A triangle is 3 ints (indices)
triStride = 3 * sizeof(int);
indices = m_indicesPtr;
indexCount = m_indexCount;
}
public void releasePinned()
{
if (m_verticesPtr != IntPtr.Zero)
{
vhandler.Free();
vertices = null;
m_verticesPtr = IntPtr.Zero;
}
if (m_indicesPtr != IntPtr.Zero)
{
ihandler.Free();
indexes = null;
m_indicesPtr = IntPtr.Zero;
}
}
/// <summary>
/// frees up the source mesh data to minimize memory - call this method after calling get*Locked() functions
/// </summary>
public void releaseSourceMeshData()
{
if (m_bdata != null)
{
m_bdata.m_triangles = null;
m_bdata.m_vertices = null;
}
}
public void releaseBuildingMeshData()
{
if (m_bdata != null)
{
m_bdata.m_triangles = null;
m_bdata.m_vertices = null;
m_bdata = null;
}
}
public void Append(IMesh newMesh)
{
if (m_indicesPtr != IntPtr.Zero || m_verticesPtr != IntPtr.Zero)
throw new NotSupportedException("Attempt to Append to a pinned Mesh");
if (!(newMesh is Mesh))
return;
foreach (Triangle t in ((Mesh)newMesh).m_bdata.m_triangles)
Add(t);
}
// Do a linear transformation of mesh.
public void TransformLinear(float[,] matrix, float[] offset)
{
if (m_indicesPtr != IntPtr.Zero || m_verticesPtr != IntPtr.Zero)
throw new NotSupportedException("Attempt to TransformLinear a pinned Mesh");
foreach (Vertex v in m_bdata.m_vertices.Keys)
{
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;
if (m_bdata == null)
return;
String fileName = name + "_" + title + ".raw";
String completePath = System.IO.Path.Combine(path, fileName);
StreamWriter sw = new StreamWriter(completePath);
foreach (Triangle t in m_bdata.m_triangles)
{
String s = t.ToStringRaw();
sw.WriteLine(s);
}
sw.Close();
}
public void TrimExcess()
{
m_bdata.m_triangles.TrimExcess();
}
public void pinMemory()
{
m_vertexCount = vertices.Length / 3;
vhandler = GCHandle.Alloc(vertices, GCHandleType.Pinned);
m_verticesPtr = vhandler.AddrOfPinnedObject();
GC.AddMemoryPressure(Buffer.ByteLength(vertices));
m_indexCount = indexes.Length;
ihandler = GCHandle.Alloc(indexes, GCHandleType.Pinned);
m_indicesPtr = ihandler.AddrOfPinnedObject();
GC.AddMemoryPressure(Buffer.ByteLength(indexes));
}
public void PrepForOde()
{
// If there isn't an unmanaged array allocated yet, do it now
if (m_verticesPtr == IntPtr.Zero)
vertices = getVertexListAsFloat();
// If there isn't an unmanaged array allocated yet, do it now
if (m_indicesPtr == IntPtr.Zero)
indexes = getIndexListAsInt();
pinMemory();
float x, y, z;
if (m_bdata.m_centroidDiv > 0)
{
m_obboffset = new Vector3(m_bdata.m_centroid.X / m_bdata.m_centroidDiv, m_bdata.m_centroid.Y / m_bdata.m_centroidDiv, m_bdata.m_centroid.Z / m_bdata.m_centroidDiv);
x = (m_bdata.m_obbXmax - m_bdata.m_obbXmin) * 0.5f;
y = (m_bdata.m_obbYmax - m_bdata.m_obbYmin) * 0.5f;
z = (m_bdata.m_obbZmax - m_bdata.m_obbZmin) * 0.5f;
}
else
{
m_obboffset = Vector3.Zero;
x = 0.5f;
y = 0.5f;
z = 0.5f;
}
m_obb = new Vector3(x, y, z);
releaseBuildingMeshData();
}
public bool ToStream(Stream st)
{
if (m_indicesPtr == IntPtr.Zero || m_verticesPtr == IntPtr.Zero)
return false;
BinaryWriter bw = new BinaryWriter(st);
bool ok = true;
try
{
bw.Write(m_vertexCount);
bw.Write(m_indexCount);
for (int i = 0; i < 3 * m_vertexCount; i++)
bw.Write(vertices[i]);
for (int i = 0; i < m_indexCount; i++)
bw.Write(indexes[i]);
bw.Write(m_obb.X);
bw.Write(m_obb.Y);
bw.Write(m_obb.Z);
bw.Write(m_obboffset.X);
bw.Write(m_obboffset.Y);
bw.Write(m_obboffset.Z);
}
catch
{
ok = false;
}
if (bw != null)
{
bw.Flush();
bw.Close();
}
return ok;
}
public static Mesh FromStream(Stream st, AMeshKey key)
{
Mesh mesh = new Mesh();
mesh.releaseBuildingMeshData();
BinaryReader br = new BinaryReader(st);
bool ok = true;
try
{
mesh.m_vertexCount = br.ReadInt32();
mesh.m_indexCount = br.ReadInt32();
int n = 3 * mesh.m_vertexCount;
mesh.vertices = new float[n];
for (int i = 0; i < n; i++)
mesh.vertices[i] = br.ReadSingle();
mesh.indexes = new int[mesh.m_indexCount];
for (int i = 0; i < mesh.m_indexCount; i++)
mesh.indexes[i] = br.ReadInt32();
mesh.m_obb.X = br.ReadSingle();
mesh.m_obb.Y = br.ReadSingle();
mesh.m_obb.Z = br.ReadSingle();
mesh.m_obboffset.X = br.ReadSingle();
mesh.m_obboffset.Y = br.ReadSingle();
mesh.m_obboffset.Z = br.ReadSingle();
}
catch
{
ok = false;
}
br.Close();
if (ok)
{
mesh.pinMemory();
mesh.Key = key;
mesh.RefCount = 1;
return mesh;
}
mesh.vertices = null;
mesh.indexes = null;
return null;
}
}
}

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,244 @@
/*
* Copyright (c) Contributors
* 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.Text;
using System.Drawing;
using System.Drawing.Imaging;
namespace PrimMesher
{
public class SculptMap
{
public int width;
public int height;
public byte[] redBytes;
public byte[] greenBytes;
public byte[] blueBytes;
public SculptMap()
{
}
public SculptMap(Bitmap bm, int lod)
{
int bmW = bm.Width;
int bmH = bm.Height;
if (bmW == 0 || bmH == 0)
throw new Exception("SculptMap: bitmap has no data");
int numLodPixels = lod * lod; // (32 * 2)^2 = 64^2 pixels for default sculpt map image
bool needsScaling = false;
bool smallMap = false;
width = bmW;
height = bmH;
while (width * height > numLodPixels * 4)
{
width >>= 1;
height >>= 1;
needsScaling = true;
}
try
{
if (needsScaling)
bm = ScaleImage(bm, width, height);
}
catch (Exception e)
{
throw new Exception("Exception in ScaleImage(): e: " + e.ToString());
}
if (width * height > numLodPixels)
{
smallMap = false;
width >>= 1;
height >>= 1;
}
else
smallMap = true;
int numBytes = (width + 1) * (height + 1);
redBytes = new byte[numBytes];
greenBytes = new byte[numBytes];
blueBytes = new byte[numBytes];
int byteNdx = 0;
Color c;
try
{
for (int y = 0; y <= height; y++)
{
for (int x = 0; x < width; x++)
{
if (smallMap)
c = bm.GetPixel(x, y < height ? y : y - 1);
else
c = bm.GetPixel(x * 2, y < height ? y * 2 : y * 2 - 1);
redBytes[byteNdx] = c.R;
greenBytes[byteNdx] = c.G;
blueBytes[byteNdx] = c.B;
++byteNdx;
}
if (smallMap)
c = bm.GetPixel(width - 1, y < height ? y : y - 1);
else
c = bm.GetPixel(width * 2 - 1, y < height ? y * 2 : y * 2 - 1);
redBytes[byteNdx] = c.R;
greenBytes[byteNdx] = c.G;
blueBytes[byteNdx] = c.B;
++byteNdx;
}
}
catch (Exception e)
{
throw new Exception("Caught exception processing byte arrays in SculptMap(): e: " + e.ToString());
}
width++;
height++;
}
public List<List<Coord>> ToRows(bool mirror)
{
int numRows = height;
int numCols = width;
List<List<Coord>> rows = new List<List<Coord>>(numRows);
float pixScale = 1.0f / 255;
int rowNdx, colNdx;
int smNdx = 0;
for (rowNdx = 0; rowNdx < numRows; rowNdx++)
{
List<Coord> row = new List<Coord>(numCols);
for (colNdx = 0; colNdx < numCols; colNdx++)
{
if (mirror)
row.Add(new Coord(-((float)redBytes[smNdx] * pixScale - 0.5f), ((float)greenBytes[smNdx] * pixScale - 0.5f), (float)blueBytes[smNdx] * pixScale - 0.5f));
else
row.Add(new Coord((float)redBytes[smNdx] * pixScale - 0.5f, (float)greenBytes[smNdx] * pixScale - 0.5f, (float)blueBytes[smNdx] * pixScale - 0.5f));
++smNdx;
}
rows.Add(row);
}
return rows;
}
private Bitmap ScaleImage(Bitmap srcImage, int destWidth, int destHeight)
{
Bitmap scaledImage = new Bitmap(destWidth, destHeight, PixelFormat.Format24bppRgb);
Color c;
// will let last step to be eventually diferent, as seems to be in sl
float xscale = (float)srcImage.Width / (float)destWidth;
float yscale = (float)srcImage.Height / (float)destHeight;
int lastsx = srcImage.Width - 1;
int lastsy = srcImage.Height - 1;
int lastdx = destWidth - 1;
int lastdy = destHeight - 1;
float sy = 0.5f;
float sx;
for (int y = 0; y < lastdy; y++)
{
sx = 0.5f;
for (int x = 0; x < lastdx; x++)
{
try
{
c = srcImage.GetPixel((int)(sx), (int)(sy));
scaledImage.SetPixel(x, y, Color.FromArgb(c.R, c.G, c.B));
}
catch (IndexOutOfRangeException)
{
}
sx += xscale;
}
try
{
c = srcImage.GetPixel(lastsx, (int)(sy));
scaledImage.SetPixel(lastdx, y, Color.FromArgb(c.R, c.G, c.B));
}
catch (IndexOutOfRangeException)
{
}
sy += yscale;
}
sx = 0.5f;
for (int x = 0; x < lastdx; x++)
{
try
{
c = srcImage.GetPixel((int)(sx), lastsy);
scaledImage.SetPixel(x, lastdy, Color.FromArgb(c.R, c.G, c.B));
}
catch (IndexOutOfRangeException)
{
}
sx += xscale;
}
try
{
c = srcImage.GetPixel(lastsx, lastsy);
scaledImage.SetPixel(lastdx, lastdy, Color.FromArgb(c.R, c.G, c.B));
}
catch (IndexOutOfRangeException)
{
}
srcImage.Dispose();
return scaledImage;
}
}
}

View File

@@ -0,0 +1,220 @@
/*
* Copyright (c) Contributors
* 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.Text;
using System.IO;
using System.Drawing;
using System.Drawing.Imaging;
namespace PrimMesher
{
public class SculptMesh
{
public List<Coord> coords;
public List<Face> faces;
public enum SculptType { sphere = 1, torus = 2, plane = 3, cylinder = 4 };
public SculptMesh(Bitmap sculptBitmap, SculptType sculptType, int lod, bool mirror, bool invert)
{
if (mirror)
invert = !invert;
SculptMap smap = new SculptMap(sculptBitmap, lod);
List<List<Coord>> rows = smap.ToRows(mirror);
_SculptMesh(rows, sculptType, invert);
}
private void _SculptMesh(List<List<Coord>> rows, SculptType sculptType, bool invert)
{
coords = new List<Coord>();
faces = new List<Face>();
sculptType = (SculptType)(((int)sculptType) & 0x07);
int width = rows[0].Count;
int p1, p2, p3, p4;
int imageX, imageY;
if (sculptType != SculptType.plane)
{
if (rows.Count % 2 == 0)
{
for (int rowNdx = 0; rowNdx < rows.Count; rowNdx++)
rows[rowNdx].Add(rows[rowNdx][0]);
}
else
{
int lastIndex = rows[0].Count - 1;
for (int i = 0; i < rows.Count; i++)
rows[i][0] = rows[i][lastIndex];
}
}
Coord topPole = rows[0][width / 2];
Coord bottomPole = rows[rows.Count - 1][width / 2];
if (sculptType == SculptType.sphere)
{
if (rows.Count % 2 == 0)
{
int count = rows[0].Count;
List<Coord> topPoleRow = new List<Coord>(count);
List<Coord> bottomPoleRow = new List<Coord>(count);
for (int i = 0; i < count; i++)
{
topPoleRow.Add(topPole);
bottomPoleRow.Add(bottomPole);
}
rows.Insert(0, topPoleRow);
rows.Add(bottomPoleRow);
}
else
{
int count = rows[0].Count;
List<Coord> topPoleRow = rows[0];
List<Coord> bottomPoleRow = rows[rows.Count - 1];
for (int i = 0; i < count; i++)
{
topPoleRow[i] = topPole;
bottomPoleRow[i] = bottomPole;
}
}
}
if (sculptType == SculptType.torus)
rows.Add(rows[0]);
int coordsDown = rows.Count;
int coordsAcross = rows[0].Count;
float widthUnit = 1.0f / (coordsAcross - 1);
float heightUnit = 1.0f / (coordsDown - 1);
for (imageY = 0; imageY < coordsDown; imageY++)
{
int rowOffset = imageY * coordsAcross;
for (imageX = 0; imageX < coordsAcross; imageX++)
{
/*
* p1-----p2
* | \ f2 |
* | \ |
* | f1 \|
* p3-----p4
*/
p4 = rowOffset + imageX;
p3 = p4 - 1;
p2 = p4 - coordsAcross;
p1 = p3 - coordsAcross;
this.coords.Add(rows[imageY][imageX]);
if (imageY > 0 && imageX > 0)
{
Face f1, f2;
if (invert)
{
f1 = new Face(p1, p4, p3);
f2 = new Face(p1, p2, p4);
}
else
{
f1 = new Face(p1, p3, p4);
f2 = new Face(p1, p4, p2);
}
this.faces.Add(f1);
this.faces.Add(f2);
}
}
}
}
/// <summary>
/// Duplicates a SculptMesh object. All object properties are copied by value, including lists.
/// </summary>
/// <returns></returns>
public SculptMesh Copy()
{
return new SculptMesh(this);
}
public SculptMesh(SculptMesh sm)
{
coords = new List<Coord>(sm.coords);
faces = new List<Face>(sm.faces);
}
public void Scale(float x, float y, float z)
{
int i;
int numVerts = this.coords.Count;
Coord m = new Coord(x, y, z);
for (i = 0; i < numVerts; i++)
this.coords[i] *= m;
}
public void DumpRaw(String path, String name, String title)
{
if (path == null)
return;
String fileName = name + "_" + title + ".raw";
String completePath = System.IO.Path.Combine(path, fileName);
StreamWriter sw = new StreamWriter(completePath);
for (int i = 0; i < this.faces.Count; i++)
{
string s = this.coords[this.faces[i].v1].ToString();
s += " " + this.coords[this.faces[i].v2].ToString();
s += " " + this.coords[this.faces[i].v3].ToString();
sw.WriteLine(s);
}
sw.Close();
}
}
}

View File

@@ -0,0 +1,58 @@
/*
* 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

View File

@@ -0,0 +1,933 @@
/*
* 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

View File

@@ -0,0 +1,683 @@
/*
* 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;
}
}

View File

@@ -0,0 +1,356 @@
/*
* 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