mirror of
https://github.com/opensim/opensim.git
synced 2026-08-05 17:05:55 +08:00
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:
@@ -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();
|
||||
|
||||
|
||||
340
OpenSim/Region/PhysicsModules/UbitMeshing/HelperTypes.cs
Normal file
340
OpenSim/Region/PhysicsModules/UbitMeshing/HelperTypes.cs
Normal 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;
|
||||
}
|
||||
}
|
||||
601
OpenSim/Region/PhysicsModules/UbitMeshing/Mesh.cs
Normal file
601
OpenSim/Region/PhysicsModules/UbitMeshing/Mesh.cs
Normal 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;
|
||||
}
|
||||
}
|
||||
}
|
||||
1424
OpenSim/Region/PhysicsModules/UbitMeshing/Meshmerizer.cs
Normal file
1424
OpenSim/Region/PhysicsModules/UbitMeshing/Meshmerizer.cs
Normal file
File diff suppressed because it is too large
Load Diff
1708
OpenSim/Region/PhysicsModules/UbitMeshing/PrimMesher.cs
Normal file
1708
OpenSim/Region/PhysicsModules/UbitMeshing/PrimMesher.cs
Normal file
File diff suppressed because it is too large
Load Diff
244
OpenSim/Region/PhysicsModules/UbitMeshing/SculptMap.cs
Normal file
244
OpenSim/Region/PhysicsModules/UbitMeshing/SculptMap.cs
Normal 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;
|
||||
}
|
||||
}
|
||||
}
|
||||
220
OpenSim/Region/PhysicsModules/UbitMeshing/SculptMesh.cs
Normal file
220
OpenSim/Region/PhysicsModules/UbitMeshing/SculptMesh.cs
Normal 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();
|
||||
}
|
||||
}
|
||||
}
|
||||
58
OpenSim/Region/PhysicsModules/UbitOdePlugin/AssemblyInfo.cs
Normal file
58
OpenSim/Region/PhysicsModules/UbitOdePlugin/AssemblyInfo.cs
Normal 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.*")]
|
||||
1847
OpenSim/Region/PhysicsModules/UbitOdePlugin/ODECharacter.cs
Normal file
1847
OpenSim/Region/PhysicsModules/UbitOdePlugin/ODECharacter.cs
Normal file
File diff suppressed because it is too large
Load Diff
1096
OpenSim/Region/PhysicsModules/UbitOdePlugin/ODEDynamics.cs
Normal file
1096
OpenSim/Region/PhysicsModules/UbitOdePlugin/ODEDynamics.cs
Normal file
File diff suppressed because it is too large
Load Diff
933
OpenSim/Region/PhysicsModules/UbitOdePlugin/ODEMeshWorker.cs
Normal file
933
OpenSim/Region/PhysicsModules/UbitOdePlugin/ODEMeshWorker.cs
Normal 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);
|
||||
}
|
||||
}
|
||||
}
|
||||
3901
OpenSim/Region/PhysicsModules/UbitOdePlugin/ODEPrim.cs
Normal file
3901
OpenSim/Region/PhysicsModules/UbitOdePlugin/ODEPrim.cs
Normal file
File diff suppressed because it is too large
Load Diff
@@ -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;
|
||||
}
|
||||
}
|
||||
356
OpenSim/Region/PhysicsModules/UbitOdePlugin/ODESitAvatar.cs
Normal file
356
OpenSim/Region/PhysicsModules/UbitOdePlugin/ODESitAvatar.cs
Normal 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;
|
||||
}
|
||||
}
|
||||
}
|
||||
2025
OpenSim/Region/PhysicsModules/UbitOdePlugin/OdeApi.cs
Normal file
2025
OpenSim/Region/PhysicsModules/UbitOdePlugin/OdeApi.cs
Normal file
File diff suppressed because it is too large
Load Diff
2930
OpenSim/Region/PhysicsModules/UbitOdePlugin/OdeScene.cs
Normal file
2930
OpenSim/Region/PhysicsModules/UbitOdePlugin/OdeScene.cs
Normal file
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user