diff options
author | Justin Clark-Casey (justincc) | 2009-11-03 19:11:09 +0000 |
---|---|---|
committer | Justin Clark-Casey (justincc) | 2009-11-03 19:11:09 +0000 |
commit | af0e5d097480de264e7501e7d5d35328be5640bb (patch) | |
tree | 4ca5cd796ed9618dc9134a6e5eee1f7e7912bee4 /OpenSim/Region/Physics | |
parent | minor: remove some mono compiler warnings (diff) | |
parent | Fixed a couple of NREs in corner cases. (diff) | |
download | opensim-SC-af0e5d097480de264e7501e7d5d35328be5640bb.zip opensim-SC-af0e5d097480de264e7501e7d5d35328be5640bb.tar.gz opensim-SC-af0e5d097480de264e7501e7d5d35328be5640bb.tar.bz2 opensim-SC-af0e5d097480de264e7501e7d5d35328be5640bb.tar.xz |
Merge branch 'master' of ssh://justincc@opensimulator.org/var/git/opensim
Diffstat (limited to 'OpenSim/Region/Physics')
-rw-r--r-- | OpenSim/Region/Physics/Manager/PhysicsActor.cs | 29 | ||||
-rw-r--r-- | OpenSim/Region/Physics/Manager/PhysicsScene.cs | 5 | ||||
-rw-r--r-- | OpenSim/Region/Physics/Meshing/Meshmerizer.cs | 14 | ||||
-rw-r--r-- | OpenSim/Region/Physics/Meshing/PrimMesher.cs | 843 | ||||
-rw-r--r-- | OpenSim/Region/Physics/OdePlugin/ODECharacter.cs | 4 | ||||
-rw-r--r-- | OpenSim/Region/Physics/OdePlugin/ODEPrim.cs | 4 | ||||
-rw-r--r-- | OpenSim/Region/Physics/OdePlugin/OdePlugin.cs | 158 |
7 files changed, 139 insertions, 918 deletions
diff --git a/OpenSim/Region/Physics/Manager/PhysicsActor.cs b/OpenSim/Region/Physics/Manager/PhysicsActor.cs index 6bfdff2..f58129d 100644 --- a/OpenSim/Region/Physics/Manager/PhysicsActor.cs +++ b/OpenSim/Region/Physics/Manager/PhysicsActor.cs | |||
@@ -52,6 +52,20 @@ namespace OpenSim.Region.Physics.Manager | |||
52 | , Absolute | 52 | , Absolute |
53 | } | 53 | } |
54 | 54 | ||
55 | public struct ContactPoint | ||
56 | { | ||
57 | public Vector3 Position; | ||
58 | public Vector3 SurfaceNormal; | ||
59 | public float PenetrationDepth; | ||
60 | |||
61 | public ContactPoint(Vector3 position, Vector3 surfaceNormal, float penetrationDepth) | ||
62 | { | ||
63 | Position = position; | ||
64 | SurfaceNormal = surfaceNormal; | ||
65 | PenetrationDepth = penetrationDepth; | ||
66 | } | ||
67 | } | ||
68 | |||
55 | public class CollisionEventUpdate : EventArgs | 69 | public class CollisionEventUpdate : EventArgs |
56 | { | 70 | { |
57 | // Raising the event on the object, so don't need to provide location.. further up the tree knows that info. | 71 | // Raising the event on the object, so don't need to provide location.. further up the tree knows that info. |
@@ -59,9 +73,9 @@ namespace OpenSim.Region.Physics.Manager | |||
59 | public int m_colliderType; | 73 | public int m_colliderType; |
60 | public int m_GenericStartEnd; | 74 | public int m_GenericStartEnd; |
61 | //public uint m_LocalID; | 75 | //public uint m_LocalID; |
62 | public Dictionary<uint,float> m_objCollisionList = new Dictionary<uint,float>(); | 76 | public Dictionary<uint, ContactPoint> m_objCollisionList = new Dictionary<uint, ContactPoint>(); |
63 | 77 | ||
64 | public CollisionEventUpdate(uint localID, int colliderType, int GenericStartEnd, Dictionary<uint, float> objCollisionList) | 78 | public CollisionEventUpdate(uint localID, int colliderType, int GenericStartEnd, Dictionary<uint, ContactPoint> objCollisionList) |
65 | { | 79 | { |
66 | m_colliderType = colliderType; | 80 | m_colliderType = colliderType; |
67 | m_GenericStartEnd = GenericStartEnd; | 81 | m_GenericStartEnd = GenericStartEnd; |
@@ -72,8 +86,7 @@ namespace OpenSim.Region.Physics.Manager | |||
72 | { | 86 | { |
73 | m_colliderType = (int) ActorTypes.Unknown; | 87 | m_colliderType = (int) ActorTypes.Unknown; |
74 | m_GenericStartEnd = 1; | 88 | m_GenericStartEnd = 1; |
75 | // m_objCollisionList = null; | 89 | m_objCollisionList = new Dictionary<uint, ContactPoint>(); |
76 | m_objCollisionList = new Dictionary<uint, float>(); | ||
77 | } | 90 | } |
78 | 91 | ||
79 | public int collidertype | 92 | public int collidertype |
@@ -88,16 +101,16 @@ namespace OpenSim.Region.Physics.Manager | |||
88 | set { m_GenericStartEnd = value; } | 101 | set { m_GenericStartEnd = value; } |
89 | } | 102 | } |
90 | 103 | ||
91 | public void addCollider(uint localID, float depth) | 104 | public void addCollider(uint localID, ContactPoint contact) |
92 | { | 105 | { |
93 | if (!m_objCollisionList.ContainsKey(localID)) | 106 | if (!m_objCollisionList.ContainsKey(localID)) |
94 | { | 107 | { |
95 | m_objCollisionList.Add(localID, depth); | 108 | m_objCollisionList.Add(localID, contact); |
96 | } | 109 | } |
97 | else | 110 | else |
98 | { | 111 | { |
99 | if (m_objCollisionList[localID] < depth) | 112 | if (m_objCollisionList[localID].PenetrationDepth < contact.PenetrationDepth) |
100 | m_objCollisionList[localID] = depth; | 113 | m_objCollisionList[localID] = contact; |
101 | } | 114 | } |
102 | } | 115 | } |
103 | } | 116 | } |
diff --git a/OpenSim/Region/Physics/Manager/PhysicsScene.cs b/OpenSim/Region/Physics/Manager/PhysicsScene.cs index bb0d18e..6d515e9 100644 --- a/OpenSim/Region/Physics/Manager/PhysicsScene.cs +++ b/OpenSim/Region/Physics/Manager/PhysicsScene.cs | |||
@@ -75,6 +75,11 @@ namespace OpenSim.Region.Physics.Manager | |||
75 | public abstract PhysicsActor AddPrimShape(string primName, PrimitiveBaseShape pbs, Vector3 position, | 75 | public abstract PhysicsActor AddPrimShape(string primName, PrimitiveBaseShape pbs, Vector3 position, |
76 | Vector3 size, Quaternion rotation, bool isPhysical); | 76 | Vector3 size, Quaternion rotation, bool isPhysical); |
77 | 77 | ||
78 | public virtual float TimeDilation | ||
79 | { | ||
80 | get { return 1.0f; } | ||
81 | } | ||
82 | |||
78 | public virtual bool SupportsNINJAJoints | 83 | public virtual bool SupportsNINJAJoints |
79 | { | 84 | { |
80 | get { return false; } | 85 | get { return false; } |
diff --git a/OpenSim/Region/Physics/Meshing/Meshmerizer.cs b/OpenSim/Region/Physics/Meshing/Meshmerizer.cs index fbe1949..fded95e 100644 --- a/OpenSim/Region/Physics/Meshing/Meshmerizer.cs +++ b/OpenSim/Region/Physics/Meshing/Meshmerizer.cs | |||
@@ -284,9 +284,13 @@ namespace OpenSim.Region.Physics.Meshing | |||
284 | 284 | ||
285 | try | 285 | try |
286 | { | 286 | { |
287 | idata = CSJ2K.J2kImage.FromBytes(primShape.SculptData); | 287 | OpenMetaverse.Imaging.ManagedImage unusedData; |
288 | OpenMetaverse.Imaging.OpenJPEG.DecodeToImage(primShape.SculptData, out unusedData, out idata); | ||
289 | unusedData = null; | ||
288 | 290 | ||
289 | if (cacheSculptMaps) | 291 | //idata = CSJ2K.J2kImage.FromBytes(primShape.SculptData); |
292 | |||
293 | if (cacheSculptMaps && idata != null) | ||
290 | { | 294 | { |
291 | try { idata.Save(decodedSculptFileName, ImageFormat.MemoryBmp); } | 295 | try { idata.Save(decodedSculptFileName, ImageFormat.MemoryBmp); } |
292 | catch (Exception e) { m_log.Error("[SCULPT]: unable to cache sculpt map " + decodedSculptFileName + " " + e.Message); } | 296 | catch (Exception e) { m_log.Error("[SCULPT]: unable to cache sculpt map " + decodedSculptFileName + " " + e.Message); } |
@@ -299,12 +303,12 @@ namespace OpenSim.Region.Physics.Meshing | |||
299 | } | 303 | } |
300 | catch (IndexOutOfRangeException) | 304 | catch (IndexOutOfRangeException) |
301 | { | 305 | { |
302 | m_log.Error("[PHYSICS]: OpenJpeg was unable to decode this. Physics Proxy generation failed"); | 306 | m_log.Error("[PHYSICS]: OpenJpeg was unable to decode this. Physics Proxy generation failed"); |
303 | return null; | 307 | return null; |
304 | } | 308 | } |
305 | catch (Exception) | 309 | catch (Exception ex) |
306 | { | 310 | { |
307 | m_log.Error("[PHYSICS]: Unable to generate a Sculpty physics proxy. Sculpty texture decode failed!"); | 311 | m_log.Error("[PHYSICS]: Unable to generate a Sculpty physics proxy. Sculpty texture decode failed: " + ex.Message); |
308 | return null; | 312 | return null; |
309 | } | 313 | } |
310 | } | 314 | } |
diff --git a/OpenSim/Region/Physics/Meshing/PrimMesher.cs b/OpenSim/Region/Physics/Meshing/PrimMesher.cs index 47ce615..c7c9160 100644 --- a/OpenSim/Region/Physics/Meshing/PrimMesher.cs +++ b/OpenSim/Region/Physics/Meshing/PrimMesher.cs | |||
@@ -67,11 +67,6 @@ namespace PrimMesher | |||
67 | Normalize(); | 67 | Normalize(); |
68 | } | 68 | } |
69 | 69 | ||
70 | public Quat Identity() | ||
71 | { | ||
72 | return new Quat(0.0f, 0.0f, 0.0f, 1.0f); | ||
73 | } | ||
74 | |||
75 | public float Length() | 70 | public float Length() |
76 | { | 71 | { |
77 | return (float)Math.Sqrt(X * X + Y * Y + Z * Z + W * W); | 72 | return (float)Math.Sqrt(X * X + Y * Y + Z * Z + W * W); |
@@ -660,7 +655,7 @@ namespace PrimMesher | |||
660 | this.faceNumbers = new List<int>(); | 655 | this.faceNumbers = new List<int>(); |
661 | 656 | ||
662 | Coord center = new Coord(0.0f, 0.0f, 0.0f); | 657 | Coord center = new Coord(0.0f, 0.0f, 0.0f); |
663 | bool hasCenter = false; | 658 | //bool hasCenter = false; |
664 | 659 | ||
665 | List<Coord> hollowCoords = new List<Coord>(); | 660 | List<Coord> hollowCoords = new List<Coord>(); |
666 | List<Coord> hollowNormals = new List<Coord>(); | 661 | List<Coord> hollowNormals = new List<Coord>(); |
@@ -727,7 +722,7 @@ namespace PrimMesher | |||
727 | else if (!simpleFace) | 722 | else if (!simpleFace) |
728 | { | 723 | { |
729 | this.coords.Add(center); | 724 | this.coords.Add(center); |
730 | hasCenter = true; | 725 | //hasCenter = true; |
731 | if (this.calcVertexNormals) | 726 | if (this.calcVertexNormals) |
732 | this.vertexNormals.Add(new Coord(0.0f, 0.0f, 1.0f)); | 727 | this.vertexNormals.Add(new Coord(0.0f, 0.0f, 1.0f)); |
733 | this.us.Add(0.0f); | 728 | this.us.Add(0.0f); |
@@ -1541,7 +1536,7 @@ namespace PrimMesher | |||
1541 | } | 1536 | } |
1542 | 1537 | ||
1543 | /// <summary> | 1538 | /// <summary> |
1544 | /// Extrudes a profile along a straight line path. Used for prim types box, cylinder, and prism. | 1539 | /// Extrudes a profile along a path. |
1545 | /// </summary> | 1540 | /// </summary> |
1546 | public void Extrude(PathType pathType) | 1541 | public void Extrude(PathType pathType) |
1547 | { | 1542 | { |
@@ -1557,7 +1552,6 @@ namespace PrimMesher | |||
1557 | if (this.calcVertexNormals) | 1552 | if (this.calcVertexNormals) |
1558 | this.normals = new List<Coord>(); | 1553 | this.normals = new List<Coord>(); |
1559 | 1554 | ||
1560 | //int step = 0; | ||
1561 | int steps = 1; | 1555 | int steps = 1; |
1562 | 1556 | ||
1563 | float length = this.pathCutEnd - this.pathCutBegin; | 1557 | float length = this.pathCutEnd - this.pathCutBegin; |
@@ -1579,20 +1573,6 @@ namespace PrimMesher | |||
1579 | if (twistTotalAbs > 0.01f) | 1573 | if (twistTotalAbs > 0.01f) |
1580 | steps += (int)(twistTotalAbs * 3.66); // dahlia's magic number | 1574 | steps += (int)(twistTotalAbs * 3.66); // dahlia's magic number |
1581 | 1575 | ||
1582 | //float start = -0.5f; | ||
1583 | //float stepSize = length / (float)steps; | ||
1584 | //float percentOfPathMultiplier = stepSize; | ||
1585 | //float xProfileScale = 1.0f; | ||
1586 | //float yProfileScale = 1.0f; | ||
1587 | //float xOffset = 0.0f; | ||
1588 | //float yOffset = 0.0f; | ||
1589 | //float zOffset = start; | ||
1590 | //float xOffsetStepIncrement = this.topShearX / steps; | ||
1591 | //float yOffsetStepIncrement = this.topShearY / steps; | ||
1592 | |||
1593 | //float percentOfPath = this.pathCutBegin; | ||
1594 | //zOffset += percentOfPath; | ||
1595 | |||
1596 | float hollow = this.hollow; | 1576 | float hollow = this.hollow; |
1597 | 1577 | ||
1598 | // sanity checks | 1578 | // sanity checks |
@@ -1662,7 +1642,6 @@ namespace PrimMesher | |||
1662 | cut2Vert = hasHollow ? profile.numOuterVerts - 1 : profile.numOuterVerts; | 1642 | cut2Vert = hasHollow ? profile.numOuterVerts - 1 : profile.numOuterVerts; |
1663 | } | 1643 | } |
1664 | 1644 | ||
1665 | |||
1666 | if (initialProfileRot != 0.0f) | 1645 | if (initialProfileRot != 0.0f) |
1667 | { | 1646 | { |
1668 | profile.AddRot(new Quat(new Coord(0.0f, 0.0f, 1.0f), initialProfileRot)); | 1647 | profile.AddRot(new Quat(new Coord(0.0f, 0.0f, 1.0f), initialProfileRot)); |
@@ -1693,24 +1672,6 @@ namespace PrimMesher | |||
1693 | path.stepsPerRevolution = stepsPerRevolution; | 1672 | path.stepsPerRevolution = stepsPerRevolution; |
1694 | 1673 | ||
1695 | path.Create(pathType, steps); | 1674 | path.Create(pathType, steps); |
1696 | /* | ||
1697 | public int twistBegin = 0; | ||
1698 | public int twistEnd = 0; | ||
1699 | public float topShearX = 0.0f; | ||
1700 | public float topShearY = 0.0f; | ||
1701 | public float pathCutBegin = 0.0f; | ||
1702 | public float pathCutEnd = 1.0f; | ||
1703 | public float dimpleBegin = 0.0f; | ||
1704 | public float dimpleEnd = 1.0f; | ||
1705 | public float skew = 0.0f; | ||
1706 | public float holeSizeX = 1.0f; // called pathScaleX in pbs | ||
1707 | public float holeSizeY = 0.25f; | ||
1708 | public float taperX = 0.0f; | ||
1709 | public float taperY = 0.0f; | ||
1710 | public float radius = 0.0f; | ||
1711 | public float revolutions = 1.0f; | ||
1712 | public int stepsPerRevolution = 24; | ||
1713 | */ | ||
1714 | 1675 | ||
1715 | bool needEndFaces = false; | 1676 | bool needEndFaces = false; |
1716 | if (pathType == PathType.Circular) | 1677 | if (pathType == PathType.Circular) |
@@ -1796,7 +1757,6 @@ namespace PrimMesher | |||
1796 | int numVerts = newLayer.coords.Count; | 1757 | int numVerts = newLayer.coords.Count; |
1797 | Face newFace = new Face(); | 1758 | Face newFace = new Face(); |
1798 | 1759 | ||
1799 | //if (step > 0) | ||
1800 | if (nodeIndex > 0) | 1760 | if (nodeIndex > 0) |
1801 | { | 1761 | { |
1802 | int startVert = coordsLen + 1; | 1762 | int startVert = coordsLen + 1; |
@@ -1812,7 +1772,6 @@ namespace PrimMesher | |||
1812 | iNext = startVert; | 1772 | iNext = startVert; |
1813 | 1773 | ||
1814 | int whichVert = i - startVert; | 1774 | int whichVert = i - startVert; |
1815 | //int whichVert2 = i - lastCoordsLen; | ||
1816 | 1775 | ||
1817 | newFace.v1 = i; | 1776 | newFace.v1 = i; |
1818 | newFace.v2 = i - numVerts; | 1777 | newFace.v2 = i - numVerts; |
@@ -1982,809 +1941,27 @@ namespace PrimMesher | |||
1982 | 1941 | ||
1983 | 1942 | ||
1984 | /// <summary> | 1943 | /// <summary> |
1944 | /// DEPRICATED - use Extrude(PathType.Linear) instead | ||
1985 | /// Extrudes a profile along a straight line path. Used for prim types box, cylinder, and prism. | 1945 | /// Extrudes a profile along a straight line path. Used for prim types box, cylinder, and prism. |
1986 | /// </summary> | 1946 | /// </summary> |
1947 | /// | ||
1987 | public void ExtrudeLinear() | 1948 | public void ExtrudeLinear() |
1988 | { | 1949 | { |
1989 | this.coords = new List<Coord>(); | 1950 | this.Extrude(PathType.Linear); |
1990 | this.faces = new List<Face>(); | ||
1991 | |||
1992 | if (this.viewerMode) | ||
1993 | { | ||
1994 | this.viewerFaces = new List<ViewerFace>(); | ||
1995 | this.calcVertexNormals = true; | ||
1996 | } | ||
1997 | |||
1998 | if (this.calcVertexNormals) | ||
1999 | this.normals = new List<Coord>(); | ||
2000 | |||
2001 | int step = 0; | ||
2002 | int steps = 1; | ||
2003 | |||
2004 | float length = this.pathCutEnd - this.pathCutBegin; | ||
2005 | normalsProcessed = false; | ||
2006 | |||
2007 | if (this.viewerMode && this.sides == 3) | ||
2008 | { | ||
2009 | // prisms don't taper well so add some vertical resolution | ||
2010 | // other prims may benefit from this but just do prisms for now | ||
2011 | if (Math.Abs(this.taperX) > 0.01 || Math.Abs(this.taperY) > 0.01) | ||
2012 | steps = (int)(steps * 4.5 * length); | ||
2013 | } | ||
2014 | |||
2015 | |||
2016 | float twistBegin = this.twistBegin / 360.0f * twoPi; | ||
2017 | float twistEnd = this.twistEnd / 360.0f * twoPi; | ||
2018 | float twistTotal = twistEnd - twistBegin; | ||
2019 | float twistTotalAbs = Math.Abs(twistTotal); | ||
2020 | if (twistTotalAbs > 0.01f) | ||
2021 | steps += (int)(twistTotalAbs * 3.66); // dahlia's magic number | ||
2022 | |||
2023 | float start = -0.5f; | ||
2024 | float stepSize = length / (float)steps; | ||
2025 | float percentOfPathMultiplier = stepSize; | ||
2026 | float xProfileScale = 1.0f; | ||
2027 | float yProfileScale = 1.0f; | ||
2028 | float xOffset = 0.0f; | ||
2029 | float yOffset = 0.0f; | ||
2030 | float zOffset = start; | ||
2031 | float xOffsetStepIncrement = this.topShearX / steps; | ||
2032 | float yOffsetStepIncrement = this.topShearY / steps; | ||
2033 | |||
2034 | float percentOfPath = this.pathCutBegin; | ||
2035 | zOffset += percentOfPath; | ||
2036 | |||
2037 | float hollow = this.hollow; | ||
2038 | |||
2039 | // sanity checks | ||
2040 | float initialProfileRot = 0.0f; | ||
2041 | if (this.sides == 3) | ||
2042 | { | ||
2043 | if (this.hollowSides == 4) | ||
2044 | { | ||
2045 | if (hollow > 0.7f) | ||
2046 | hollow = 0.7f; | ||
2047 | hollow *= 0.707f; | ||
2048 | } | ||
2049 | else hollow *= 0.5f; | ||
2050 | } | ||
2051 | else if (this.sides == 4) | ||
2052 | { | ||
2053 | initialProfileRot = 1.25f * (float)Math.PI; | ||
2054 | if (this.hollowSides != 4) | ||
2055 | hollow *= 0.707f; | ||
2056 | } | ||
2057 | else if (this.sides == 24 && this.hollowSides == 4) | ||
2058 | hollow *= 1.414f; | ||
2059 | |||
2060 | Profile profile = new Profile(this.sides, this.profileStart, this.profileEnd, hollow, this.hollowSides, true, calcVertexNormals); | ||
2061 | this.errorMessage = profile.errorMessage; | ||
2062 | |||
2063 | this.numPrimFaces = profile.numPrimFaces; | ||
2064 | |||
2065 | int cut1Vert = -1; | ||
2066 | int cut2Vert = -1; | ||
2067 | if (hasProfileCut) | ||
2068 | { | ||
2069 | cut1Vert = hasHollow ? profile.coords.Count - 1 : 0; | ||
2070 | cut2Vert = hasHollow ? profile.numOuterVerts - 1 : profile.numOuterVerts; | ||
2071 | } | ||
2072 | |||
2073 | if (initialProfileRot != 0.0f) | ||
2074 | { | ||
2075 | profile.AddRot(new Quat(new Coord(0.0f, 0.0f, 1.0f), initialProfileRot)); | ||
2076 | if (viewerMode) | ||
2077 | profile.MakeFaceUVs(); | ||
2078 | } | ||
2079 | |||
2080 | Coord lastCutNormal1 = new Coord(); | ||
2081 | Coord lastCutNormal2 = new Coord(); | ||
2082 | float lastV = 1.0f; | ||
2083 | |||
2084 | bool done = false; | ||
2085 | while (!done) | ||
2086 | { | ||
2087 | Profile newLayer = profile.Copy(); | ||
2088 | |||
2089 | if (this.taperX == 0.0f) | ||
2090 | xProfileScale = 1.0f; | ||
2091 | else if (this.taperX > 0.0f) | ||
2092 | xProfileScale = 1.0f - percentOfPath * this.taperX; | ||
2093 | else xProfileScale = 1.0f + (1.0f - percentOfPath) * this.taperX; | ||
2094 | |||
2095 | if (this.taperY == 0.0f) | ||
2096 | yProfileScale = 1.0f; | ||
2097 | else if (this.taperY > 0.0f) | ||
2098 | yProfileScale = 1.0f - percentOfPath * this.taperY; | ||
2099 | else yProfileScale = 1.0f + (1.0f - percentOfPath) * this.taperY; | ||
2100 | |||
2101 | if (xProfileScale != 1.0f || yProfileScale != 1.0f) | ||
2102 | newLayer.Scale(xProfileScale, yProfileScale); | ||
2103 | |||
2104 | float twist = twistBegin + twistTotal * percentOfPath; | ||
2105 | if (twist != 0.0f) | ||
2106 | newLayer.AddRot(new Quat(new Coord(0.0f, 0.0f, 1.0f), twist)); | ||
2107 | |||
2108 | newLayer.AddPos(xOffset, yOffset, zOffset); | ||
2109 | |||
2110 | if (step == 0) | ||
2111 | { | ||
2112 | newLayer.FlipNormals(); | ||
2113 | |||
2114 | // add the top faces to the viewerFaces list here | ||
2115 | if (this.viewerMode) | ||
2116 | { | ||
2117 | Coord faceNormal = newLayer.faceNormal; | ||
2118 | ViewerFace newViewerFace = new ViewerFace(profile.bottomFaceNumber); | ||
2119 | int numFaces = newLayer.faces.Count; | ||
2120 | List<Face> faces = newLayer.faces; | ||
2121 | |||
2122 | for (int i = 0; i < numFaces; i++) | ||
2123 | { | ||
2124 | Face face = faces[i]; | ||
2125 | newViewerFace.v1 = newLayer.coords[face.v1]; | ||
2126 | newViewerFace.v2 = newLayer.coords[face.v2]; | ||
2127 | newViewerFace.v3 = newLayer.coords[face.v3]; | ||
2128 | |||
2129 | newViewerFace.coordIndex1 = face.v1; | ||
2130 | newViewerFace.coordIndex2 = face.v2; | ||
2131 | newViewerFace.coordIndex3 = face.v3; | ||
2132 | |||
2133 | newViewerFace.n1 = faceNormal; | ||
2134 | newViewerFace.n2 = faceNormal; | ||
2135 | newViewerFace.n3 = faceNormal; | ||
2136 | |||
2137 | newViewerFace.uv1 = newLayer.faceUVs[face.v1]; | ||
2138 | newViewerFace.uv2 = newLayer.faceUVs[face.v2]; | ||
2139 | newViewerFace.uv3 = newLayer.faceUVs[face.v3]; | ||
2140 | |||
2141 | this.viewerFaces.Add(newViewerFace); | ||
2142 | } | ||
2143 | } | ||
2144 | } | ||
2145 | |||
2146 | // append this layer | ||
2147 | |||
2148 | int coordsLen = this.coords.Count; | ||
2149 | int lastCoordsLen = coordsLen; | ||
2150 | newLayer.AddValue2FaceVertexIndices(coordsLen); | ||
2151 | |||
2152 | this.coords.AddRange(newLayer.coords); | ||
2153 | |||
2154 | if (this.calcVertexNormals) | ||
2155 | { | ||
2156 | newLayer.AddValue2FaceNormalIndices(this.normals.Count); | ||
2157 | this.normals.AddRange(newLayer.vertexNormals); | ||
2158 | } | ||
2159 | |||
2160 | if (percentOfPath < this.pathCutBegin + 0.01f || percentOfPath > this.pathCutEnd - 0.01f) | ||
2161 | this.faces.AddRange(newLayer.faces); | ||
2162 | |||
2163 | // fill faces between layers | ||
2164 | |||
2165 | int numVerts = newLayer.coords.Count; | ||
2166 | Face newFace = new Face(); | ||
2167 | |||
2168 | if (step > 0) | ||
2169 | { | ||
2170 | int startVert = coordsLen + 1; | ||
2171 | int endVert = this.coords.Count; | ||
2172 | |||
2173 | if (sides < 5 || this.hasProfileCut || hollow > 0.0f) | ||
2174 | startVert--; | ||
2175 | |||
2176 | for (int i = startVert; i < endVert; i++) | ||
2177 | { | ||
2178 | int iNext = i + 1; | ||
2179 | if (i == endVert - 1) | ||
2180 | iNext = startVert; | ||
2181 | |||
2182 | int whichVert = i - startVert; | ||
2183 | //int whichVert2 = i - lastCoordsLen; | ||
2184 | |||
2185 | newFace.v1 = i; | ||
2186 | newFace.v2 = i - numVerts; | ||
2187 | newFace.v3 = iNext - numVerts; | ||
2188 | this.faces.Add(newFace); | ||
2189 | |||
2190 | newFace.v2 = iNext - numVerts; | ||
2191 | newFace.v3 = iNext; | ||
2192 | this.faces.Add(newFace); | ||
2193 | |||
2194 | if (this.viewerMode) | ||
2195 | { | ||
2196 | // add the side faces to the list of viewerFaces here | ||
2197 | //int primFaceNum = 1; | ||
2198 | //if (whichVert >= sides) | ||
2199 | // primFaceNum = 2; | ||
2200 | int primFaceNum = profile.faceNumbers[whichVert]; | ||
2201 | |||
2202 | ViewerFace newViewerFace1 = new ViewerFace(primFaceNum); | ||
2203 | ViewerFace newViewerFace2 = new ViewerFace(primFaceNum); | ||
2204 | |||
2205 | float u1 = newLayer.us[whichVert]; | ||
2206 | float u2 = 1.0f; | ||
2207 | if (whichVert < newLayer.us.Count - 1) | ||
2208 | u2 = newLayer.us[whichVert + 1]; | ||
2209 | |||
2210 | if (whichVert == cut1Vert || whichVert == cut2Vert) | ||
2211 | { | ||
2212 | u1 = 0.0f; | ||
2213 | u2 = 1.0f; | ||
2214 | } | ||
2215 | else if (sides < 5) | ||
2216 | { // boxes and prisms have one texture face per side of the prim, so the U values have to be scaled | ||
2217 | // to reflect the entire texture width | ||
2218 | u1 *= sides; | ||
2219 | u2 *= sides; | ||
2220 | u2 -= (int)u1; | ||
2221 | u1 -= (int)u1; | ||
2222 | if (u2 < 0.1f) | ||
2223 | u2 = 1.0f; | ||
2224 | |||
2225 | //newViewerFace2.primFaceNumber = newViewerFace1.primFaceNumber = whichVert + 1; | ||
2226 | } | ||
2227 | |||
2228 | newViewerFace1.uv1.U = u1; | ||
2229 | newViewerFace1.uv2.U = u1; | ||
2230 | newViewerFace1.uv3.U = u2; | ||
2231 | |||
2232 | newViewerFace1.uv1.V = 1.0f - percentOfPath; | ||
2233 | newViewerFace1.uv2.V = lastV; | ||
2234 | newViewerFace1.uv3.V = lastV; | ||
2235 | |||
2236 | newViewerFace2.uv1.U = u1; | ||
2237 | newViewerFace2.uv2.U = u2; | ||
2238 | newViewerFace2.uv3.U = u2; | ||
2239 | |||
2240 | newViewerFace2.uv1.V = 1.0f - percentOfPath; | ||
2241 | newViewerFace2.uv2.V = lastV; | ||
2242 | newViewerFace2.uv3.V = 1.0f - percentOfPath; | ||
2243 | |||
2244 | newViewerFace1.v1 = this.coords[i]; | ||
2245 | newViewerFace1.v2 = this.coords[i - numVerts]; | ||
2246 | newViewerFace1.v3 = this.coords[iNext - numVerts]; | ||
2247 | |||
2248 | newViewerFace2.v1 = this.coords[i]; | ||
2249 | newViewerFace2.v2 = this.coords[iNext - numVerts]; | ||
2250 | newViewerFace2.v3 = this.coords[iNext]; | ||
2251 | |||
2252 | newViewerFace1.coordIndex1 = i; | ||
2253 | newViewerFace1.coordIndex2 = i - numVerts; | ||
2254 | newViewerFace1.coordIndex3 = iNext - numVerts; | ||
2255 | |||
2256 | newViewerFace2.coordIndex1 = i; | ||
2257 | newViewerFace2.coordIndex2 = iNext - numVerts; | ||
2258 | newViewerFace2.coordIndex3 = iNext; | ||
2259 | |||
2260 | // profile cut faces | ||
2261 | if (whichVert == cut1Vert) | ||
2262 | { | ||
2263 | newViewerFace1.n1 = newLayer.cutNormal1; | ||
2264 | newViewerFace1.n2 = newViewerFace1.n3 = lastCutNormal1; | ||
2265 | |||
2266 | newViewerFace2.n1 = newViewerFace2.n3 = newLayer.cutNormal1; | ||
2267 | newViewerFace2.n2 = lastCutNormal1; | ||
2268 | } | ||
2269 | else if (whichVert == cut2Vert) | ||
2270 | { | ||
2271 | newViewerFace1.n1 = newLayer.cutNormal2; | ||
2272 | newViewerFace1.n2 = newViewerFace1.n3 = lastCutNormal2; | ||
2273 | |||
2274 | newViewerFace2.n1 = newViewerFace2.n3 = newLayer.cutNormal2; | ||
2275 | newViewerFace2.n2 = lastCutNormal2; | ||
2276 | } | ||
2277 | |||
2278 | else // outer and hollow faces | ||
2279 | { | ||
2280 | if ((sides < 5 && whichVert < newLayer.numOuterVerts) || (hollowSides < 5 && whichVert >= newLayer.numOuterVerts)) | ||
2281 | { | ||
2282 | newViewerFace1.CalcSurfaceNormal(); | ||
2283 | newViewerFace2.CalcSurfaceNormal(); | ||
2284 | } | ||
2285 | else | ||
2286 | { | ||
2287 | newViewerFace1.n1 = this.normals[i]; | ||
2288 | newViewerFace1.n2 = this.normals[i - numVerts]; | ||
2289 | newViewerFace1.n3 = this.normals[iNext - numVerts]; | ||
2290 | |||
2291 | newViewerFace2.n1 = this.normals[i]; | ||
2292 | newViewerFace2.n2 = this.normals[iNext - numVerts]; | ||
2293 | newViewerFace2.n3 = this.normals[iNext]; | ||
2294 | } | ||
2295 | } | ||
2296 | |||
2297 | //newViewerFace2.primFaceNumber = newViewerFace1.primFaceNumber = newLayer.faceNumbers[whichVert]; | ||
2298 | |||
2299 | this.viewerFaces.Add(newViewerFace1); | ||
2300 | this.viewerFaces.Add(newViewerFace2); | ||
2301 | |||
2302 | } | ||
2303 | } | ||
2304 | } | ||
2305 | |||
2306 | lastCutNormal1 = newLayer.cutNormal1; | ||
2307 | lastCutNormal2 = newLayer.cutNormal2; | ||
2308 | lastV = 1.0f - percentOfPath; | ||
2309 | |||
2310 | // calc the step for the next iteration of the loop | ||
2311 | |||
2312 | if (step < steps) | ||
2313 | { | ||
2314 | step += 1; | ||
2315 | percentOfPath += percentOfPathMultiplier; | ||
2316 | xOffset += xOffsetStepIncrement; | ||
2317 | yOffset += yOffsetStepIncrement; | ||
2318 | zOffset += stepSize; | ||
2319 | if (percentOfPath > this.pathCutEnd) | ||
2320 | done = true; | ||
2321 | } | ||
2322 | else done = true; | ||
2323 | |||
2324 | if (done && viewerMode) | ||
2325 | { | ||
2326 | // add the top faces to the viewerFaces list here | ||
2327 | Coord faceNormal = newLayer.faceNormal; | ||
2328 | ViewerFace newViewerFace = new ViewerFace(); | ||
2329 | newViewerFace.primFaceNumber = 0; | ||
2330 | int numFaces = newLayer.faces.Count; | ||
2331 | List<Face> faces = newLayer.faces; | ||
2332 | |||
2333 | for (int i = 0; i < numFaces; i++) | ||
2334 | { | ||
2335 | Face face = faces[i]; | ||
2336 | newViewerFace.v1 = newLayer.coords[face.v1 - coordsLen]; | ||
2337 | newViewerFace.v2 = newLayer.coords[face.v2 - coordsLen]; | ||
2338 | newViewerFace.v3 = newLayer.coords[face.v3 - coordsLen]; | ||
2339 | |||
2340 | newViewerFace.coordIndex1 = face.v1 - coordsLen; | ||
2341 | newViewerFace.coordIndex2 = face.v2 - coordsLen; | ||
2342 | newViewerFace.coordIndex3 = face.v3 - coordsLen; | ||
2343 | |||
2344 | newViewerFace.n1 = faceNormal; | ||
2345 | newViewerFace.n2 = faceNormal; | ||
2346 | newViewerFace.n3 = faceNormal; | ||
2347 | |||
2348 | newViewerFace.uv1 = newLayer.faceUVs[face.v1 - coordsLen]; | ||
2349 | newViewerFace.uv2 = newLayer.faceUVs[face.v2 - coordsLen]; | ||
2350 | newViewerFace.uv3 = newLayer.faceUVs[face.v3 - coordsLen]; | ||
2351 | |||
2352 | this.viewerFaces.Add(newViewerFace); | ||
2353 | } | ||
2354 | } | ||
2355 | } | ||
2356 | } | 1951 | } |
2357 | 1952 | ||
2358 | 1953 | ||
2359 | /// <summary> | 1954 | /// <summary> |
1955 | /// DEPRICATED - use Extrude(PathType.Circular) instead | ||
2360 | /// Extrude a profile into a circular path prim mesh. Used for prim types torus, tube, and ring. | 1956 | /// Extrude a profile into a circular path prim mesh. Used for prim types torus, tube, and ring. |
2361 | /// </summary> | 1957 | /// </summary> |
1958 | /// | ||
2362 | public void ExtrudeCircular() | 1959 | public void ExtrudeCircular() |
2363 | { | 1960 | { |
2364 | this.coords = new List<Coord>(); | 1961 | this.Extrude(PathType.Circular); |
2365 | this.faces = new List<Face>(); | ||
2366 | |||
2367 | if (this.viewerMode) | ||
2368 | { | ||
2369 | this.viewerFaces = new List<ViewerFace>(); | ||
2370 | this.calcVertexNormals = true; | ||
2371 | } | ||
2372 | |||
2373 | if (this.calcVertexNormals) | ||
2374 | this.normals = new List<Coord>(); | ||
2375 | |||
2376 | int step = 0; | ||
2377 | int steps = 24; | ||
2378 | |||
2379 | normalsProcessed = false; | ||
2380 | |||
2381 | float twistBegin = this.twistBegin / 360.0f * twoPi; | ||
2382 | float twistEnd = this.twistEnd / 360.0f * twoPi; | ||
2383 | float twistTotal = twistEnd - twistBegin; | ||
2384 | |||
2385 | // if the profile has a lot of twist, add more layers otherwise the layers may overlap | ||
2386 | // and the resulting mesh may be quite inaccurate. This method is arbitrary and doesn't | ||
2387 | // accurately match the viewer | ||
2388 | float twistTotalAbs = Math.Abs(twistTotal); | ||
2389 | if (twistTotalAbs > 0.01f) | ||
2390 | { | ||
2391 | if (twistTotalAbs > Math.PI * 1.5f) | ||
2392 | steps *= 2; | ||
2393 | if (twistTotalAbs > Math.PI * 3.0f) | ||
2394 | steps *= 2; | ||
2395 | } | ||
2396 | |||
2397 | float yPathScale = this.holeSizeY * 0.5f; | ||
2398 | float pathLength = this.pathCutEnd - this.pathCutBegin; | ||
2399 | float totalSkew = this.skew * 2.0f * pathLength; | ||
2400 | float skewStart = this.pathCutBegin * 2.0f * this.skew - this.skew; | ||
2401 | float xOffsetTopShearXFactor = this.topShearX * (0.25f + 0.5f * (0.5f - this.holeSizeY)); | ||
2402 | float yShearCompensation = 1.0f + Math.Abs(this.topShearY) * 0.25f; | ||
2403 | |||
2404 | // It's not quite clear what pushY (Y top shear) does, but subtracting it from the start and end | ||
2405 | // angles appears to approximate it's effects on path cut. Likewise, adding it to the angle used | ||
2406 | // to calculate the sine for generating the path radius appears to approximate it's effects there | ||
2407 | // too, but there are some subtle differences in the radius which are noticeable as the prim size | ||
2408 | // increases and it may affect megaprims quite a bit. The effect of the Y top shear parameter on | ||
2409 | // the meshes generated with this technique appear nearly identical in shape to the same prims when | ||
2410 | // displayed by the viewer. | ||
2411 | |||
2412 | float startAngle = (twoPi * this.pathCutBegin * this.revolutions) - this.topShearY * 0.9f; | ||
2413 | float endAngle = (twoPi * this.pathCutEnd * this.revolutions) - this.topShearY * 0.9f; | ||
2414 | float stepSize = twoPi / this.stepsPerRevolution; | ||
2415 | |||
2416 | step = (int)(startAngle / stepSize); | ||
2417 | int firstStep = step; | ||
2418 | float angle = startAngle; | ||
2419 | float hollow = this.hollow; | ||
2420 | |||
2421 | // sanity checks | ||
2422 | float initialProfileRot = 0.0f; | ||
2423 | if (this.sides == 3) | ||
2424 | { | ||
2425 | initialProfileRot = (float)Math.PI; | ||
2426 | if (this.hollowSides == 4) | ||
2427 | { | ||
2428 | if (hollow > 0.7f) | ||
2429 | hollow = 0.7f; | ||
2430 | hollow *= 0.707f; | ||
2431 | } | ||
2432 | else hollow *= 0.5f; | ||
2433 | } | ||
2434 | else if (this.sides == 4) | ||
2435 | { | ||
2436 | initialProfileRot = 0.25f * (float)Math.PI; | ||
2437 | if (this.hollowSides != 4) | ||
2438 | hollow *= 0.707f; | ||
2439 | } | ||
2440 | else if (this.sides > 4) | ||
2441 | { | ||
2442 | initialProfileRot = (float)Math.PI; | ||
2443 | if (this.hollowSides == 4) | ||
2444 | { | ||
2445 | if (hollow > 0.7f) | ||
2446 | hollow = 0.7f; | ||
2447 | hollow /= 0.7f; | ||
2448 | } | ||
2449 | } | ||
2450 | |||
2451 | bool needEndFaces = false; | ||
2452 | if (this.pathCutBegin != 0.0f || this.pathCutEnd != 1.0f) | ||
2453 | needEndFaces = true; | ||
2454 | else if (this.taperX != 0.0f || this.taperY != 0.0f) | ||
2455 | needEndFaces = true; | ||
2456 | else if (this.skew != 0.0f) | ||
2457 | needEndFaces = true; | ||
2458 | else if (twistTotal != 0.0f) | ||
2459 | needEndFaces = true; | ||
2460 | else if (this.radius != 0.0f) | ||
2461 | needEndFaces = true; | ||
2462 | |||
2463 | Profile profile = new Profile(this.sides, this.profileStart, this.profileEnd, hollow, this.hollowSides, needEndFaces, calcVertexNormals); | ||
2464 | this.errorMessage = profile.errorMessage; | ||
2465 | |||
2466 | this.numPrimFaces = profile.numPrimFaces; | ||
2467 | |||
2468 | int cut1Vert = -1; | ||
2469 | int cut2Vert = -1; | ||
2470 | if (hasProfileCut) | ||
2471 | { | ||
2472 | cut1Vert = hasHollow ? profile.coords.Count - 1 : 0; | ||
2473 | cut2Vert = hasHollow ? profile.numOuterVerts - 1 : profile.numOuterVerts; | ||
2474 | } | ||
2475 | |||
2476 | if (initialProfileRot != 0.0f) | ||
2477 | { | ||
2478 | profile.AddRot(new Quat(new Coord(0.0f, 0.0f, 1.0f), initialProfileRot)); | ||
2479 | if (viewerMode) | ||
2480 | profile.MakeFaceUVs(); | ||
2481 | } | ||
2482 | |||
2483 | Coord lastCutNormal1 = new Coord(); | ||
2484 | Coord lastCutNormal2 = new Coord(); | ||
2485 | float lastV = 1.0f; | ||
2486 | |||
2487 | bool done = false; | ||
2488 | while (!done) // loop through the length of the path and add the layers | ||
2489 | { | ||
2490 | bool isEndLayer = false; | ||
2491 | if (angle <= startAngle + .01f || angle >= endAngle - .01f) | ||
2492 | isEndLayer = true; | ||
2493 | |||
2494 | Profile newLayer = profile.Copy(); | ||
2495 | |||
2496 | float xProfileScale = (1.0f - Math.Abs(this.skew)) * this.holeSizeX; | ||
2497 | float yProfileScale = this.holeSizeY; | ||
2498 | |||
2499 | float percentOfPath = angle / (twoPi * this.revolutions); | ||
2500 | float percentOfAngles = (angle - startAngle) / (endAngle - startAngle); | ||
2501 | |||
2502 | if (this.taperX > 0.01f) | ||
2503 | xProfileScale *= 1.0f - percentOfPath * this.taperX; | ||
2504 | else if (this.taperX < -0.01f) | ||
2505 | xProfileScale *= 1.0f + (1.0f - percentOfPath) * this.taperX; | ||
2506 | |||
2507 | if (this.taperY > 0.01f) | ||
2508 | yProfileScale *= 1.0f - percentOfPath * this.taperY; | ||
2509 | else if (this.taperY < -0.01f) | ||
2510 | yProfileScale *= 1.0f + (1.0f - percentOfPath) * this.taperY; | ||
2511 | |||
2512 | if (xProfileScale != 1.0f || yProfileScale != 1.0f) | ||
2513 | newLayer.Scale(xProfileScale, yProfileScale); | ||
2514 | |||
2515 | float radiusScale = 1.0f; | ||
2516 | if (this.radius > 0.001f) | ||
2517 | radiusScale = 1.0f - this.radius * percentOfPath; | ||
2518 | else if (this.radius < 0.001f) | ||
2519 | radiusScale = 1.0f + this.radius * (1.0f - percentOfPath); | ||
2520 | |||
2521 | float twist = twistBegin + twistTotal * percentOfPath; | ||
2522 | |||
2523 | float xOffset = 0.5f * (skewStart + totalSkew * percentOfAngles); | ||
2524 | xOffset += (float)Math.Sin(angle) * xOffsetTopShearXFactor; | ||
2525 | |||
2526 | float yOffset = yShearCompensation * (float)Math.Cos(angle) * (0.5f - yPathScale) * radiusScale; | ||
2527 | |||
2528 | float zOffset = (float)Math.Sin(angle + this.topShearY) * (0.5f - yPathScale) * radiusScale; | ||
2529 | |||
2530 | // next apply twist rotation to the profile layer | ||
2531 | if (twistTotal != 0.0f || twistBegin != 0.0f) | ||
2532 | newLayer.AddRot(new Quat(new Coord(0.0f, 0.0f, 1.0f), twist)); | ||
2533 | |||
2534 | // now orient the rotation of the profile layer relative to it's position on the path | ||
2535 | // adding taperY to the angle used to generate the quat appears to approximate the viewer | ||
2536 | newLayer.AddRot(new Quat(new Coord(1.0f, 0.0f, 0.0f), angle + this.topShearY)); | ||
2537 | newLayer.AddPos(xOffset, yOffset, zOffset); | ||
2538 | |||
2539 | if (isEndLayer && angle <= startAngle + .01f) | ||
2540 | { | ||
2541 | newLayer.FlipNormals(); | ||
2542 | |||
2543 | // add the top faces to the viewerFaces list here | ||
2544 | if (this.viewerMode && needEndFaces) | ||
2545 | { | ||
2546 | Coord faceNormal = newLayer.faceNormal; | ||
2547 | ViewerFace newViewerFace = new ViewerFace(); | ||
2548 | newViewerFace.primFaceNumber = 0; | ||
2549 | foreach (Face face in newLayer.faces) | ||
2550 | { | ||
2551 | newViewerFace.v1 = newLayer.coords[face.v1]; | ||
2552 | newViewerFace.v2 = newLayer.coords[face.v2]; | ||
2553 | newViewerFace.v3 = newLayer.coords[face.v3]; | ||
2554 | |||
2555 | newViewerFace.coordIndex1 = face.v1; | ||
2556 | newViewerFace.coordIndex2 = face.v2; | ||
2557 | newViewerFace.coordIndex3 = face.v3; | ||
2558 | |||
2559 | newViewerFace.n1 = faceNormal; | ||
2560 | newViewerFace.n2 = faceNormal; | ||
2561 | newViewerFace.n3 = faceNormal; | ||
2562 | |||
2563 | newViewerFace.uv1 = newLayer.faceUVs[face.v1]; | ||
2564 | newViewerFace.uv2 = newLayer.faceUVs[face.v2]; | ||
2565 | newViewerFace.uv3 = newLayer.faceUVs[face.v3]; | ||
2566 | |||
2567 | this.viewerFaces.Add(newViewerFace); | ||
2568 | } | ||
2569 | } | ||
2570 | } | ||
2571 | |||
2572 | // append the layer and fill in the sides | ||
2573 | |||
2574 | int coordsLen = this.coords.Count; | ||
2575 | newLayer.AddValue2FaceVertexIndices(coordsLen); | ||
2576 | |||
2577 | this.coords.AddRange(newLayer.coords); | ||
2578 | |||
2579 | if (this.calcVertexNormals) | ||
2580 | { | ||
2581 | newLayer.AddValue2FaceNormalIndices(this.normals.Count); | ||
2582 | this.normals.AddRange(newLayer.vertexNormals); | ||
2583 | } | ||
2584 | |||
2585 | if (isEndLayer) | ||
2586 | this.faces.AddRange(newLayer.faces); | ||
2587 | |||
2588 | // fill faces between layers | ||
2589 | |||
2590 | int numVerts = newLayer.coords.Count; | ||
2591 | Face newFace = new Face(); | ||
2592 | if (step > firstStep) | ||
2593 | { | ||
2594 | int startVert = coordsLen + 1; | ||
2595 | int endVert = this.coords.Count; | ||
2596 | |||
2597 | if (sides < 5 || this.hasProfileCut || hollow > 0.0f) | ||
2598 | startVert--; | ||
2599 | |||
2600 | for (int i = startVert; i < endVert; i++) | ||
2601 | { | ||
2602 | int iNext = i + 1; | ||
2603 | if (i == endVert - 1) | ||
2604 | iNext = startVert; | ||
2605 | |||
2606 | int whichVert = i - startVert; | ||
2607 | |||
2608 | newFace.v1 = i; | ||
2609 | newFace.v2 = i - numVerts; | ||
2610 | newFace.v3 = iNext - numVerts; | ||
2611 | this.faces.Add(newFace); | ||
2612 | |||
2613 | newFace.v2 = iNext - numVerts; | ||
2614 | newFace.v3 = iNext; | ||
2615 | this.faces.Add(newFace); | ||
2616 | |||
2617 | if (this.viewerMode) | ||
2618 | { | ||
2619 | int primFaceNumber = profile.faceNumbers[whichVert]; | ||
2620 | if (!needEndFaces) | ||
2621 | primFaceNumber -= 1; | ||
2622 | |||
2623 | // add the side faces to the list of viewerFaces here | ||
2624 | ViewerFace newViewerFace1 = new ViewerFace(primFaceNumber); | ||
2625 | ViewerFace newViewerFace2 = new ViewerFace(primFaceNumber); | ||
2626 | float u1 = newLayer.us[whichVert]; | ||
2627 | float u2 = 1.0f; | ||
2628 | if (whichVert < newLayer.us.Count - 1) | ||
2629 | u2 = newLayer.us[whichVert + 1]; | ||
2630 | |||
2631 | if (whichVert == cut1Vert || whichVert == cut2Vert) | ||
2632 | { | ||
2633 | u1 = 0.0f; | ||
2634 | u2 = 1.0f; | ||
2635 | } | ||
2636 | else if (sides < 5) | ||
2637 | { // boxes and prisms have one texture face per side of the prim, so the U values have to be scaled | ||
2638 | // to reflect the entire texture width | ||
2639 | u1 *= sides; | ||
2640 | u2 *= sides; | ||
2641 | u2 -= (int)u1; | ||
2642 | u1 -= (int)u1; | ||
2643 | if (u2 < 0.1f) | ||
2644 | u2 = 1.0f; | ||
2645 | |||
2646 | //newViewerFace2.primFaceNumber = newViewerFace1.primFaceNumber = whichVert + 1; | ||
2647 | } | ||
2648 | |||
2649 | newViewerFace1.uv1.U = u1; | ||
2650 | newViewerFace1.uv2.U = u1; | ||
2651 | newViewerFace1.uv3.U = u2; | ||
2652 | |||
2653 | newViewerFace1.uv1.V = 1.0f - percentOfPath; | ||
2654 | newViewerFace1.uv2.V = lastV; | ||
2655 | newViewerFace1.uv3.V = lastV; | ||
2656 | |||
2657 | newViewerFace2.uv1.U = u1; | ||
2658 | newViewerFace2.uv2.U = u2; | ||
2659 | newViewerFace2.uv3.U = u2; | ||
2660 | |||
2661 | newViewerFace2.uv1.V = 1.0f - percentOfPath; | ||
2662 | newViewerFace2.uv2.V = lastV; | ||
2663 | newViewerFace2.uv3.V = 1.0f - percentOfPath; | ||
2664 | |||
2665 | newViewerFace1.v1 = this.coords[i]; | ||
2666 | newViewerFace1.v2 = this.coords[i - numVerts]; | ||
2667 | newViewerFace1.v3 = this.coords[iNext - numVerts]; | ||
2668 | |||
2669 | newViewerFace2.v1 = this.coords[i]; | ||
2670 | newViewerFace2.v2 = this.coords[iNext - numVerts]; | ||
2671 | newViewerFace2.v3 = this.coords[iNext]; | ||
2672 | |||
2673 | newViewerFace1.coordIndex1 = i; | ||
2674 | newViewerFace1.coordIndex2 = i - numVerts; | ||
2675 | newViewerFace1.coordIndex3 = iNext - numVerts; | ||
2676 | |||
2677 | newViewerFace2.coordIndex1 = i; | ||
2678 | newViewerFace2.coordIndex2 = iNext - numVerts; | ||
2679 | newViewerFace2.coordIndex3 = iNext; | ||
2680 | |||
2681 | // profile cut faces | ||
2682 | if (whichVert == cut1Vert) | ||
2683 | { | ||
2684 | newViewerFace1.n1 = newLayer.cutNormal1; | ||
2685 | newViewerFace1.n2 = newViewerFace1.n3 = lastCutNormal1; | ||
2686 | |||
2687 | newViewerFace2.n1 = newViewerFace2.n3 = newLayer.cutNormal1; | ||
2688 | newViewerFace2.n2 = lastCutNormal1; | ||
2689 | } | ||
2690 | else if (whichVert == cut2Vert) | ||
2691 | { | ||
2692 | newViewerFace1.n1 = newLayer.cutNormal2; | ||
2693 | newViewerFace1.n2 = newViewerFace1.n3 = lastCutNormal2; | ||
2694 | |||
2695 | newViewerFace2.n1 = newViewerFace2.n3 = newLayer.cutNormal2; | ||
2696 | newViewerFace2.n2 = lastCutNormal2; | ||
2697 | } | ||
2698 | else // periphery faces | ||
2699 | { | ||
2700 | if (sides < 5 && whichVert < newLayer.numOuterVerts) | ||
2701 | { | ||
2702 | newViewerFace1.n1 = this.normals[i]; | ||
2703 | newViewerFace1.n2 = this.normals[i - numVerts]; | ||
2704 | newViewerFace1.n3 = this.normals[i - numVerts]; | ||
2705 | |||
2706 | newViewerFace2.n1 = this.normals[i]; | ||
2707 | newViewerFace2.n2 = this.normals[i - numVerts]; | ||
2708 | newViewerFace2.n3 = this.normals[i]; | ||
2709 | } | ||
2710 | else if (hollowSides < 5 && whichVert >= newLayer.numOuterVerts) | ||
2711 | { | ||
2712 | newViewerFace1.n1 = this.normals[iNext]; | ||
2713 | newViewerFace1.n2 = this.normals[iNext - numVerts]; | ||
2714 | newViewerFace1.n3 = this.normals[iNext - numVerts]; | ||
2715 | |||
2716 | newViewerFace2.n1 = this.normals[iNext]; | ||
2717 | newViewerFace2.n2 = this.normals[iNext - numVerts]; | ||
2718 | newViewerFace2.n3 = this.normals[iNext]; | ||
2719 | } | ||
2720 | else | ||
2721 | { | ||
2722 | newViewerFace1.n1 = this.normals[i]; | ||
2723 | newViewerFace1.n2 = this.normals[i - numVerts]; | ||
2724 | newViewerFace1.n3 = this.normals[iNext - numVerts]; | ||
2725 | |||
2726 | newViewerFace2.n1 = this.normals[i]; | ||
2727 | newViewerFace2.n2 = this.normals[iNext - numVerts]; | ||
2728 | newViewerFace2.n3 = this.normals[iNext]; | ||
2729 | } | ||
2730 | } | ||
2731 | |||
2732 | //newViewerFace1.primFaceNumber = newViewerFace2.primFaceNumber = newLayer.faceNumbers[whichVert]; | ||
2733 | this.viewerFaces.Add(newViewerFace1); | ||
2734 | this.viewerFaces.Add(newViewerFace2); | ||
2735 | |||
2736 | } | ||
2737 | } | ||
2738 | } | ||
2739 | |||
2740 | lastCutNormal1 = newLayer.cutNormal1; | ||
2741 | lastCutNormal2 = newLayer.cutNormal2; | ||
2742 | lastV = 1.0f - percentOfPath; | ||
2743 | |||
2744 | // calculate terms for next iteration | ||
2745 | // calculate the angle for the next iteration of the loop | ||
2746 | |||
2747 | if (angle >= endAngle - 0.01) | ||
2748 | done = true; | ||
2749 | else | ||
2750 | { | ||
2751 | step += 1; | ||
2752 | angle = stepSize * step; | ||
2753 | if (angle > endAngle) | ||
2754 | angle = endAngle; | ||
2755 | } | ||
2756 | |||
2757 | if (done && viewerMode && needEndFaces) | ||
2758 | { | ||
2759 | // add the bottom faces to the viewerFaces list here | ||
2760 | Coord faceNormal = newLayer.faceNormal; | ||
2761 | ViewerFace newViewerFace = new ViewerFace(); | ||
2762 | //newViewerFace.primFaceNumber = newLayer.bottomFaceNumber + 1; | ||
2763 | newViewerFace.primFaceNumber = newLayer.bottomFaceNumber; | ||
2764 | foreach (Face face in newLayer.faces) | ||
2765 | { | ||
2766 | newViewerFace.v1 = newLayer.coords[face.v1 - coordsLen]; | ||
2767 | newViewerFace.v2 = newLayer.coords[face.v2 - coordsLen]; | ||
2768 | newViewerFace.v3 = newLayer.coords[face.v3 - coordsLen]; | ||
2769 | |||
2770 | newViewerFace.coordIndex1 = face.v1 - coordsLen; | ||
2771 | newViewerFace.coordIndex2 = face.v2 - coordsLen; | ||
2772 | newViewerFace.coordIndex3 = face.v3 - coordsLen; | ||
2773 | |||
2774 | newViewerFace.n1 = faceNormal; | ||
2775 | newViewerFace.n2 = faceNormal; | ||
2776 | newViewerFace.n3 = faceNormal; | ||
2777 | |||
2778 | newViewerFace.uv1 = newLayer.faceUVs[face.v1 - coordsLen]; | ||
2779 | newViewerFace.uv2 = newLayer.faceUVs[face.v2 - coordsLen]; | ||
2780 | newViewerFace.uv3 = newLayer.faceUVs[face.v3 - coordsLen]; | ||
2781 | |||
2782 | this.viewerFaces.Add(newViewerFace); | ||
2783 | } | ||
2784 | } | ||
2785 | } | ||
2786 | } | 1962 | } |
2787 | 1963 | ||
1964 | |||
2788 | private Coord SurfaceNormal(Coord c1, Coord c2, Coord c3) | 1965 | private Coord SurfaceNormal(Coord c1, Coord c2, Coord c3) |
2789 | { | 1966 | { |
2790 | Coord edge1 = new Coord(c2.X - c1.X, c2.Y - c1.Y, c2.Z - c1.Z); | 1967 | Coord edge1 = new Coord(c2.X - c1.X, c2.Y - c1.Y, c2.Z - c1.Z); |
diff --git a/OpenSim/Region/Physics/OdePlugin/ODECharacter.cs b/OpenSim/Region/Physics/OdePlugin/ODECharacter.cs index c86bc62..1bc4a25 100644 --- a/OpenSim/Region/Physics/OdePlugin/ODECharacter.cs +++ b/OpenSim/Region/Physics/OdePlugin/ODECharacter.cs | |||
@@ -1209,11 +1209,11 @@ namespace OpenSim.Region.Physics.OdePlugin | |||
1209 | m_requestedUpdateFrequency = 0; | 1209 | m_requestedUpdateFrequency = 0; |
1210 | m_eventsubscription = 0; | 1210 | m_eventsubscription = 0; |
1211 | } | 1211 | } |
1212 | public void AddCollisionEvent(uint CollidedWith, float depth) | 1212 | public void AddCollisionEvent(uint CollidedWith, ContactPoint contact) |
1213 | { | 1213 | { |
1214 | if (m_eventsubscription > 0) | 1214 | if (m_eventsubscription > 0) |
1215 | { | 1215 | { |
1216 | CollisionEventsThisFrame.addCollider(CollidedWith, depth); | 1216 | CollisionEventsThisFrame.addCollider(CollidedWith, contact); |
1217 | } | 1217 | } |
1218 | } | 1218 | } |
1219 | 1219 | ||
diff --git a/OpenSim/Region/Physics/OdePlugin/ODEPrim.cs b/OpenSim/Region/Physics/OdePlugin/ODEPrim.cs index 49bbab9..fa42023 100644 --- a/OpenSim/Region/Physics/OdePlugin/ODEPrim.cs +++ b/OpenSim/Region/Physics/OdePlugin/ODEPrim.cs | |||
@@ -2958,11 +2958,11 @@ Console.WriteLine(" JointCreateFixed"); | |||
2958 | m_eventsubscription = 0; | 2958 | m_eventsubscription = 0; |
2959 | } | 2959 | } |
2960 | 2960 | ||
2961 | public void AddCollisionEvent(uint CollidedWith, float depth) | 2961 | public void AddCollisionEvent(uint CollidedWith, ContactPoint contact) |
2962 | { | 2962 | { |
2963 | if (CollisionEventsThisFrame == null) | 2963 | if (CollisionEventsThisFrame == null) |
2964 | CollisionEventsThisFrame = new CollisionEventUpdate(); | 2964 | CollisionEventsThisFrame = new CollisionEventUpdate(); |
2965 | CollisionEventsThisFrame.addCollider(CollidedWith,depth); | 2965 | CollisionEventsThisFrame.addCollider(CollidedWith, contact); |
2966 | } | 2966 | } |
2967 | 2967 | ||
2968 | public void SendCollisions() | 2968 | public void SendCollisions() |
diff --git a/OpenSim/Region/Physics/OdePlugin/OdePlugin.cs b/OpenSim/Region/Physics/OdePlugin/OdePlugin.cs index 73ad15e..3c9a31d 100644 --- a/OpenSim/Region/Physics/OdePlugin/OdePlugin.cs +++ b/OpenSim/Region/Physics/OdePlugin/OdePlugin.cs | |||
@@ -159,6 +159,7 @@ namespace OpenSim.Region.Physics.OdePlugin | |||
159 | 159 | ||
160 | private float ODE_STEPSIZE = 0.020f; | 160 | private float ODE_STEPSIZE = 0.020f; |
161 | private float metersInSpace = 29.9f; | 161 | private float metersInSpace = 29.9f; |
162 | private float m_timeDilation = 1.0f; | ||
162 | 163 | ||
163 | public float gravityx = 0f; | 164 | public float gravityx = 0f; |
164 | public float gravityy = 0f; | 165 | public float gravityy = 0f; |
@@ -177,8 +178,8 @@ namespace OpenSim.Region.Physics.OdePlugin | |||
177 | //private int m_returncollisions = 10; | 178 | //private int m_returncollisions = 10; |
178 | 179 | ||
179 | private readonly IntPtr contactgroup; | 180 | private readonly IntPtr contactgroup; |
180 | internal IntPtr LandGeom; | ||
181 | 181 | ||
182 | internal IntPtr LandGeom; | ||
182 | internal IntPtr WaterGeom; | 183 | internal IntPtr WaterGeom; |
183 | 184 | ||
184 | private float nmTerrainContactFriction = 255.0f; | 185 | private float nmTerrainContactFriction = 255.0f; |
@@ -250,7 +251,7 @@ namespace OpenSim.Region.Physics.OdePlugin | |||
250 | private bool m_NINJA_physics_joints_enabled = false; | 251 | private bool m_NINJA_physics_joints_enabled = false; |
251 | //private Dictionary<String, IntPtr> jointpart_name_map = new Dictionary<String,IntPtr>(); | 252 | //private Dictionary<String, IntPtr> jointpart_name_map = new Dictionary<String,IntPtr>(); |
252 | private readonly Dictionary<String, List<PhysicsJoint>> joints_connecting_actor = new Dictionary<String, List<PhysicsJoint>>(); | 253 | private readonly Dictionary<String, List<PhysicsJoint>> joints_connecting_actor = new Dictionary<String, List<PhysicsJoint>>(); |
253 | private d.ContactGeom[] contacts = new d.ContactGeom[80]; | 254 | private d.ContactGeom[] contacts; |
254 | private readonly List<PhysicsJoint> requestedJointsToBeCreated = new List<PhysicsJoint>(); // lock only briefly. accessed by external code (to request new joints) and by OdeScene.Simulate() to move those joints into pending/active | 255 | private readonly List<PhysicsJoint> requestedJointsToBeCreated = new List<PhysicsJoint>(); // lock only briefly. accessed by external code (to request new joints) and by OdeScene.Simulate() to move those joints into pending/active |
255 | private readonly List<PhysicsJoint> pendingJoints = new List<PhysicsJoint>(); // can lock for longer. accessed only by OdeScene. | 256 | private readonly List<PhysicsJoint> pendingJoints = new List<PhysicsJoint>(); // can lock for longer. accessed only by OdeScene. |
256 | private readonly List<PhysicsJoint> activeJoints = new List<PhysicsJoint>(); // can lock for longer. accessed only by OdeScene. | 257 | private readonly List<PhysicsJoint> activeJoints = new List<PhysicsJoint>(); // can lock for longer. accessed only by OdeScene. |
@@ -396,6 +397,8 @@ namespace OpenSim.Region.Physics.OdePlugin | |||
396 | avStandupTensor = 550000f; | 397 | avStandupTensor = 550000f; |
397 | } | 398 | } |
398 | 399 | ||
400 | int contactsPerCollision = 80; | ||
401 | |||
399 | if (m_config != null) | 402 | if (m_config != null) |
400 | { | 403 | { |
401 | IConfig physicsconfig = m_config.Configs["ODEPhysicsSettings"]; | 404 | IConfig physicsconfig = m_config.Configs["ODEPhysicsSettings"]; |
@@ -438,6 +441,8 @@ namespace OpenSim.Region.Physics.OdePlugin | |||
438 | avCapRadius = physicsconfig.GetFloat("av_capsule_radius", 0.37f); | 441 | avCapRadius = physicsconfig.GetFloat("av_capsule_radius", 0.37f); |
439 | avCapsuleTilted = physicsconfig.GetBoolean("av_capsule_tilted", true); | 442 | avCapsuleTilted = physicsconfig.GetBoolean("av_capsule_tilted", true); |
440 | 443 | ||
444 | contactsPerCollision = physicsconfig.GetInt("contacts_per_collision", 80); | ||
445 | |||
441 | geomContactPointsStartthrottle = physicsconfig.GetInt("geom_contactpoints_start_throttling", 3); | 446 | geomContactPointsStartthrottle = physicsconfig.GetInt("geom_contactpoints_start_throttling", 3); |
442 | geomUpdatesPerThrottledUpdate = physicsconfig.GetInt("geom_updates_before_throttled_update", 15); | 447 | geomUpdatesPerThrottledUpdate = physicsconfig.GetInt("geom_updates_before_throttled_update", 15); |
443 | geomCrossingFailuresBeforeOutofbounds = physicsconfig.GetInt("geom_crossing_failures_before_outofbounds", 5); | 448 | geomCrossingFailuresBeforeOutofbounds = physicsconfig.GetInt("geom_crossing_failures_before_outofbounds", 5); |
@@ -475,10 +480,11 @@ namespace OpenSim.Region.Physics.OdePlugin | |||
475 | 480 | ||
476 | m_NINJA_physics_joints_enabled = physicsconfig.GetBoolean("use_NINJA_physics_joints", false); | 481 | m_NINJA_physics_joints_enabled = physicsconfig.GetBoolean("use_NINJA_physics_joints", false); |
477 | minimumGroundFlightOffset = physicsconfig.GetFloat("minimum_ground_flight_offset", 3f); | 482 | minimumGroundFlightOffset = physicsconfig.GetFloat("minimum_ground_flight_offset", 3f); |
478 | |||
479 | } | 483 | } |
480 | } | 484 | } |
481 | 485 | ||
486 | contacts = new d.ContactGeom[contactsPerCollision]; | ||
487 | |||
482 | staticPrimspace = new IntPtr[(int)(300 / metersInSpace), (int)(300 / metersInSpace)]; | 488 | staticPrimspace = new IntPtr[(int)(300 / metersInSpace), (int)(300 / metersInSpace)]; |
483 | 489 | ||
484 | // Centeral contact friction and bounce | 490 | // Centeral contact friction and bounce |
@@ -771,7 +777,9 @@ namespace OpenSim.Region.Physics.OdePlugin | |||
771 | 777 | ||
772 | lock (contacts) | 778 | lock (contacts) |
773 | { | 779 | { |
774 | count = d.Collide(g1, g2, contacts.GetLength(0), contacts, d.ContactGeom.SizeOf); | 780 | count = d.Collide(g1, g2, contacts.Length, contacts, d.ContactGeom.SizeOf); |
781 | if (count > contacts.Length) | ||
782 | m_log.Error("[PHYSICS]: Got " + count + " contacts when we asked for a maximum of " + contacts.Length); | ||
775 | } | 783 | } |
776 | } | 784 | } |
777 | catch (SEHException) | 785 | catch (SEHException) |
@@ -799,7 +807,7 @@ namespace OpenSim.Region.Physics.OdePlugin | |||
799 | p2 = PANull; | 807 | p2 = PANull; |
800 | } | 808 | } |
801 | 809 | ||
802 | float max_collision_depth = 0f; | 810 | ContactPoint maxDepthContact = new ContactPoint(); |
803 | if (p1.CollisionScore + count >= float.MaxValue) | 811 | if (p1.CollisionScore + count >= float.MaxValue) |
804 | p1.CollisionScore = 0; | 812 | p1.CollisionScore = 0; |
805 | p1.CollisionScore += count; | 813 | p1.CollisionScore += count; |
@@ -810,9 +818,17 @@ namespace OpenSim.Region.Physics.OdePlugin | |||
810 | 818 | ||
811 | for (int i = 0; i < count; i++) | 819 | for (int i = 0; i < count; i++) |
812 | { | 820 | { |
821 | d.ContactGeom curContact = contacts[i]; | ||
813 | 822 | ||
823 | if (curContact.depth > maxDepthContact.PenetrationDepth) | ||
824 | { | ||
825 | maxDepthContact = new ContactPoint( | ||
826 | new Vector3(curContact.pos.X, curContact.pos.Y, curContact.pos.Z), | ||
827 | new Vector3(curContact.normal.X, curContact.normal.Y, curContact.normal.Z), | ||
828 | curContact.depth | ||
829 | ); | ||
830 | } | ||
814 | 831 | ||
815 | max_collision_depth = (contacts[i].depth > max_collision_depth) ? contacts[i].depth : max_collision_depth; | ||
816 | //m_log.Warn("[CCOUNT]: " + count); | 832 | //m_log.Warn("[CCOUNT]: " + count); |
817 | IntPtr joint; | 833 | IntPtr joint; |
818 | // If we're colliding with terrain, use 'TerrainContact' instead of contact. | 834 | // If we're colliding with terrain, use 'TerrainContact' instead of contact. |
@@ -829,7 +845,7 @@ namespace OpenSim.Region.Physics.OdePlugin | |||
829 | p2.CollidingObj = true; | 845 | p2.CollidingObj = true; |
830 | break; | 846 | break; |
831 | case (int)ActorTypes.Prim: | 847 | case (int)ActorTypes.Prim: |
832 | if (p2.Velocity.X > 0 || p2.Velocity.Y > 0 || p2.Velocity.Z > 0) | 848 | if (p2.Velocity.LengthSquared() > 0.0f) |
833 | p2.CollidingObj = true; | 849 | p2.CollidingObj = true; |
834 | break; | 850 | break; |
835 | case (int)ActorTypes.Unknown: | 851 | case (int)ActorTypes.Unknown: |
@@ -845,14 +861,14 @@ namespace OpenSim.Region.Physics.OdePlugin | |||
845 | #region InterPenetration Handling - Unintended physics explosions | 861 | #region InterPenetration Handling - Unintended physics explosions |
846 | # region disabled code1 | 862 | # region disabled code1 |
847 | 863 | ||
848 | if (contacts[i].depth >= 0.08f) | 864 | if (curContact.depth >= 0.08f) |
849 | { | 865 | { |
850 | //This is disabled at the moment only because it needs more tweaking | 866 | //This is disabled at the moment only because it needs more tweaking |
851 | //It will eventually be uncommented | 867 | //It will eventually be uncommented |
852 | /* | 868 | /* |
853 | if (contacts[i].depth >= 1.00f) | 869 | if (contact.depth >= 1.00f) |
854 | { | 870 | { |
855 | //m_log.Debug("[PHYSICS]: " + contacts[i].depth.ToString()); | 871 | //m_log.Debug("[PHYSICS]: " + contact.depth.ToString()); |
856 | } | 872 | } |
857 | 873 | ||
858 | //If you interpenetrate a prim with an agent | 874 | //If you interpenetrate a prim with an agent |
@@ -862,37 +878,37 @@ namespace OpenSim.Region.Physics.OdePlugin | |||
862 | p2.PhysicsActorType == (int) ActorTypes.Prim)) | 878 | p2.PhysicsActorType == (int) ActorTypes.Prim)) |
863 | { | 879 | { |
864 | 880 | ||
865 | //contacts[i].depth = contacts[i].depth * 4.15f; | 881 | //contact.depth = contact.depth * 4.15f; |
866 | /* | 882 | /* |
867 | if (p2.PhysicsActorType == (int) ActorTypes.Agent) | 883 | if (p2.PhysicsActorType == (int) ActorTypes.Agent) |
868 | { | 884 | { |
869 | p2.CollidingObj = true; | 885 | p2.CollidingObj = true; |
870 | contacts[i].depth = 0.003f; | 886 | contact.depth = 0.003f; |
871 | p2.Velocity = p2.Velocity + new PhysicsVector(0, 0, 2.5f); | 887 | p2.Velocity = p2.Velocity + new PhysicsVector(0, 0, 2.5f); |
872 | OdeCharacter character = (OdeCharacter) p2; | 888 | OdeCharacter character = (OdeCharacter) p2; |
873 | character.SetPidStatus(true); | 889 | character.SetPidStatus(true); |
874 | contacts[i].pos = new d.Vector3(contacts[i].pos.X + (p1.Size.X / 2), contacts[i].pos.Y + (p1.Size.Y / 2), contacts[i].pos.Z + (p1.Size.Z / 2)); | 890 | contact.pos = new d.Vector3(contact.pos.X + (p1.Size.X / 2), contact.pos.Y + (p1.Size.Y / 2), contact.pos.Z + (p1.Size.Z / 2)); |
875 | 891 | ||
876 | } | 892 | } |
877 | else | 893 | else |
878 | { | 894 | { |
879 | 895 | ||
880 | //contacts[i].depth = 0.0000000f; | 896 | //contact.depth = 0.0000000f; |
881 | } | 897 | } |
882 | if (p1.PhysicsActorType == (int) ActorTypes.Agent) | 898 | if (p1.PhysicsActorType == (int) ActorTypes.Agent) |
883 | { | 899 | { |
884 | 900 | ||
885 | p1.CollidingObj = true; | 901 | p1.CollidingObj = true; |
886 | contacts[i].depth = 0.003f; | 902 | contact.depth = 0.003f; |
887 | p1.Velocity = p1.Velocity + new PhysicsVector(0, 0, 2.5f); | 903 | p1.Velocity = p1.Velocity + new PhysicsVector(0, 0, 2.5f); |
888 | contacts[i].pos = new d.Vector3(contacts[i].pos.X + (p2.Size.X / 2), contacts[i].pos.Y + (p2.Size.Y / 2), contacts[i].pos.Z + (p2.Size.Z / 2)); | 904 | contact.pos = new d.Vector3(contact.pos.X + (p2.Size.X / 2), contact.pos.Y + (p2.Size.Y / 2), contact.pos.Z + (p2.Size.Z / 2)); |
889 | OdeCharacter character = (OdeCharacter)p1; | 905 | OdeCharacter character = (OdeCharacter)p1; |
890 | character.SetPidStatus(true); | 906 | character.SetPidStatus(true); |
891 | } | 907 | } |
892 | else | 908 | else |
893 | { | 909 | { |
894 | 910 | ||
895 | //contacts[i].depth = 0.0000000f; | 911 | //contact.depth = 0.0000000f; |
896 | } | 912 | } |
897 | 913 | ||
898 | 914 | ||
@@ -917,7 +933,7 @@ namespace OpenSim.Region.Physics.OdePlugin | |||
917 | //AddPhysicsActorTaint(p2); | 933 | //AddPhysicsActorTaint(p2); |
918 | //} | 934 | //} |
919 | 935 | ||
920 | //if (contacts[i].depth >= 0.25f) | 936 | //if (contact.depth >= 0.25f) |
921 | //{ | 937 | //{ |
922 | // Don't collide, one or both prim will expld. | 938 | // Don't collide, one or both prim will expld. |
923 | 939 | ||
@@ -935,21 +951,21 @@ namespace OpenSim.Region.Physics.OdePlugin | |||
935 | //AddPhysicsActorTaint(p2); | 951 | //AddPhysicsActorTaint(p2); |
936 | //} | 952 | //} |
937 | 953 | ||
938 | //contacts[i].depth = contacts[i].depth / 8f; | 954 | //contact.depth = contact.depth / 8f; |
939 | //contacts[i].normal = new d.Vector3(0, 0, 1); | 955 | //contact.normal = new d.Vector3(0, 0, 1); |
940 | //} | 956 | //} |
941 | //if (op1.m_disabled || op2.m_disabled) | 957 | //if (op1.m_disabled || op2.m_disabled) |
942 | //{ | 958 | //{ |
943 | //Manually disabled objects stay disabled | 959 | //Manually disabled objects stay disabled |
944 | //contacts[i].depth = 0f; | 960 | //contact.depth = 0f; |
945 | //} | 961 | //} |
946 | #endregion | 962 | #endregion |
947 | } | 963 | } |
948 | */ | 964 | */ |
949 | #endregion | 965 | #endregion |
950 | if (contacts[i].depth >= 1.00f) | 966 | if (curContact.depth >= 1.00f) |
951 | { | 967 | { |
952 | //m_log.Info("[P]: " + contacts[i].depth.ToString()); | 968 | //m_log.Info("[P]: " + contact.depth.ToString()); |
953 | if ((p2.PhysicsActorType == (int) ActorTypes.Agent && | 969 | if ((p2.PhysicsActorType == (int) ActorTypes.Agent && |
954 | p1.PhysicsActorType == (int) ActorTypes.Unknown) || | 970 | p1.PhysicsActorType == (int) ActorTypes.Unknown) || |
955 | (p1.PhysicsActorType == (int) ActorTypes.Agent && | 971 | (p1.PhysicsActorType == (int) ActorTypes.Agent && |
@@ -962,12 +978,12 @@ namespace OpenSim.Region.Physics.OdePlugin | |||
962 | OdeCharacter character = (OdeCharacter) p2; | 978 | OdeCharacter character = (OdeCharacter) p2; |
963 | 979 | ||
964 | //p2.CollidingObj = true; | 980 | //p2.CollidingObj = true; |
965 | contacts[i].depth = 0.00000003f; | 981 | curContact.depth = 0.00000003f; |
966 | p2.Velocity = p2.Velocity + new Vector3(0f, 0f, 0.5f); | 982 | p2.Velocity = p2.Velocity + new Vector3(0f, 0f, 0.5f); |
967 | contacts[i].pos = | 983 | curContact.pos = |
968 | new d.Vector3(contacts[i].pos.X + (p1.Size.X/2), | 984 | new d.Vector3(curContact.pos.X + (p1.Size.X/2), |
969 | contacts[i].pos.Y + (p1.Size.Y/2), | 985 | curContact.pos.Y + (p1.Size.Y/2), |
970 | contacts[i].pos.Z + (p1.Size.Z/2)); | 986 | curContact.pos.Z + (p1.Size.Z/2)); |
971 | character.SetPidStatus(true); | 987 | character.SetPidStatus(true); |
972 | } | 988 | } |
973 | } | 989 | } |
@@ -980,12 +996,12 @@ namespace OpenSim.Region.Physics.OdePlugin | |||
980 | OdeCharacter character = (OdeCharacter) p1; | 996 | OdeCharacter character = (OdeCharacter) p1; |
981 | 997 | ||
982 | //p2.CollidingObj = true; | 998 | //p2.CollidingObj = true; |
983 | contacts[i].depth = 0.00000003f; | 999 | curContact.depth = 0.00000003f; |
984 | p1.Velocity = p1.Velocity + new Vector3(0f, 0f, 0.5f); | 1000 | p1.Velocity = p1.Velocity + new Vector3(0f, 0f, 0.5f); |
985 | contacts[i].pos = | 1001 | curContact.pos = |
986 | new d.Vector3(contacts[i].pos.X + (p1.Size.X/2), | 1002 | new d.Vector3(curContact.pos.X + (p1.Size.X/2), |
987 | contacts[i].pos.Y + (p1.Size.Y/2), | 1003 | curContact.pos.Y + (p1.Size.Y/2), |
988 | contacts[i].pos.Z + (p1.Size.Z/2)); | 1004 | curContact.pos.Z + (p1.Size.Z/2)); |
989 | character.SetPidStatus(true); | 1005 | character.SetPidStatus(true); |
990 | } | 1006 | } |
991 | } | 1007 | } |
@@ -1007,16 +1023,15 @@ namespace OpenSim.Region.Physics.OdePlugin | |||
1007 | if (!skipThisContact && (p2 is OdePrim) && (((OdePrim)p2).m_isVolumeDetect)) | 1023 | if (!skipThisContact && (p2 is OdePrim) && (((OdePrim)p2).m_isVolumeDetect)) |
1008 | skipThisContact = true; // No collision on volume detect prims | 1024 | skipThisContact = true; // No collision on volume detect prims |
1009 | 1025 | ||
1010 | if (!skipThisContact && contacts[i].depth < 0f) | 1026 | if (!skipThisContact && curContact.depth < 0f) |
1011 | skipThisContact = true; | 1027 | skipThisContact = true; |
1012 | 1028 | ||
1013 | if (!skipThisContact && checkDupe(contacts[i], p2.PhysicsActorType)) | 1029 | if (!skipThisContact && checkDupe(curContact, p2.PhysicsActorType)) |
1014 | skipThisContact = true; | 1030 | skipThisContact = true; |
1015 | 1031 | ||
1016 | int maxContactsbeforedeath = 4000; | 1032 | const int maxContactsbeforedeath = 4000; |
1017 | joint = IntPtr.Zero; | 1033 | joint = IntPtr.Zero; |
1018 | 1034 | ||
1019 | |||
1020 | if (!skipThisContact) | 1035 | if (!skipThisContact) |
1021 | { | 1036 | { |
1022 | // If we're colliding against terrain | 1037 | // If we're colliding against terrain |
@@ -1027,8 +1042,8 @@ namespace OpenSim.Region.Physics.OdePlugin | |||
1027 | (Math.Abs(p2.Velocity.X) > 0.01f || Math.Abs(p2.Velocity.Y) > 0.01f)) | 1042 | (Math.Abs(p2.Velocity.X) > 0.01f || Math.Abs(p2.Velocity.Y) > 0.01f)) |
1028 | { | 1043 | { |
1029 | // Use the movement terrain contact | 1044 | // Use the movement terrain contact |
1030 | AvatarMovementTerrainContact.geom = contacts[i]; | 1045 | AvatarMovementTerrainContact.geom = curContact; |
1031 | _perloopContact.Add(contacts[i]); | 1046 | _perloopContact.Add(curContact); |
1032 | if (m_global_contactcount < maxContactsbeforedeath) | 1047 | if (m_global_contactcount < maxContactsbeforedeath) |
1033 | { | 1048 | { |
1034 | joint = d.JointCreateContact(world, contactgroup, ref AvatarMovementTerrainContact); | 1049 | joint = d.JointCreateContact(world, contactgroup, ref AvatarMovementTerrainContact); |
@@ -1040,8 +1055,8 @@ namespace OpenSim.Region.Physics.OdePlugin | |||
1040 | if (p2.PhysicsActorType == (int)ActorTypes.Agent) | 1055 | if (p2.PhysicsActorType == (int)ActorTypes.Agent) |
1041 | { | 1056 | { |
1042 | // Use the non moving terrain contact | 1057 | // Use the non moving terrain contact |
1043 | TerrainContact.geom = contacts[i]; | 1058 | TerrainContact.geom = curContact; |
1044 | _perloopContact.Add(contacts[i]); | 1059 | _perloopContact.Add(curContact); |
1045 | if (m_global_contactcount < maxContactsbeforedeath) | 1060 | if (m_global_contactcount < maxContactsbeforedeath) |
1046 | { | 1061 | { |
1047 | joint = d.JointCreateContact(world, contactgroup, ref TerrainContact); | 1062 | joint = d.JointCreateContact(world, contactgroup, ref TerrainContact); |
@@ -1066,8 +1081,8 @@ namespace OpenSim.Region.Physics.OdePlugin | |||
1066 | material = ((OdePrim)p2).m_material; | 1081 | material = ((OdePrim)p2).m_material; |
1067 | 1082 | ||
1068 | //m_log.DebugFormat("Material: {0}", material); | 1083 | //m_log.DebugFormat("Material: {0}", material); |
1069 | m_materialContacts[material, movintYN].geom = contacts[i]; | 1084 | m_materialContacts[material, movintYN].geom = curContact; |
1070 | _perloopContact.Add(contacts[i]); | 1085 | _perloopContact.Add(curContact); |
1071 | 1086 | ||
1072 | if (m_global_contactcount < maxContactsbeforedeath) | 1087 | if (m_global_contactcount < maxContactsbeforedeath) |
1073 | { | 1088 | { |
@@ -1092,8 +1107,8 @@ namespace OpenSim.Region.Physics.OdePlugin | |||
1092 | if (p2 is OdePrim) | 1107 | if (p2 is OdePrim) |
1093 | material = ((OdePrim)p2).m_material; | 1108 | material = ((OdePrim)p2).m_material; |
1094 | //m_log.DebugFormat("Material: {0}", material); | 1109 | //m_log.DebugFormat("Material: {0}", material); |
1095 | m_materialContacts[material, movintYN].geom = contacts[i]; | 1110 | m_materialContacts[material, movintYN].geom = curContact; |
1096 | _perloopContact.Add(contacts[i]); | 1111 | _perloopContact.Add(curContact); |
1097 | 1112 | ||
1098 | if (m_global_contactcount < maxContactsbeforedeath) | 1113 | if (m_global_contactcount < maxContactsbeforedeath) |
1099 | { | 1114 | { |
@@ -1121,20 +1136,20 @@ namespace OpenSim.Region.Physics.OdePlugin | |||
1121 | */ | 1136 | */ |
1122 | //WaterContact.surface.soft_cfm = 0.0000f; | 1137 | //WaterContact.surface.soft_cfm = 0.0000f; |
1123 | //WaterContact.surface.soft_erp = 0.00000f; | 1138 | //WaterContact.surface.soft_erp = 0.00000f; |
1124 | if (contacts[i].depth > 0.1f) | 1139 | if (curContact.depth > 0.1f) |
1125 | { | 1140 | { |
1126 | contacts[i].depth *= 52; | 1141 | curContact.depth *= 52; |
1127 | //contacts[i].normal = new d.Vector3(0, 0, 1); | 1142 | //contact.normal = new d.Vector3(0, 0, 1); |
1128 | //contacts[i].pos = new d.Vector3(0, 0, contacts[i].pos.Z - 5f); | 1143 | //contact.pos = new d.Vector3(0, 0, contact.pos.Z - 5f); |
1129 | } | 1144 | } |
1130 | WaterContact.geom = contacts[i]; | 1145 | WaterContact.geom = curContact; |
1131 | _perloopContact.Add(contacts[i]); | 1146 | _perloopContact.Add(curContact); |
1132 | if (m_global_contactcount < maxContactsbeforedeath) | 1147 | if (m_global_contactcount < maxContactsbeforedeath) |
1133 | { | 1148 | { |
1134 | joint = d.JointCreateContact(world, contactgroup, ref WaterContact); | 1149 | joint = d.JointCreateContact(world, contactgroup, ref WaterContact); |
1135 | m_global_contactcount++; | 1150 | m_global_contactcount++; |
1136 | } | 1151 | } |
1137 | //m_log.Info("[PHYSICS]: Prim Water Contact" + contacts[i].depth); | 1152 | //m_log.Info("[PHYSICS]: Prim Water Contact" + contact.depth); |
1138 | } | 1153 | } |
1139 | else | 1154 | else |
1140 | { | 1155 | { |
@@ -1145,8 +1160,8 @@ namespace OpenSim.Region.Physics.OdePlugin | |||
1145 | if ((Math.Abs(p2.Velocity.X) > 0.01f || Math.Abs(p2.Velocity.Y) > 0.01f)) | 1160 | if ((Math.Abs(p2.Velocity.X) > 0.01f || Math.Abs(p2.Velocity.Y) > 0.01f)) |
1146 | { | 1161 | { |
1147 | // Use the Movement prim contact | 1162 | // Use the Movement prim contact |
1148 | AvatarMovementprimContact.geom = contacts[i]; | 1163 | AvatarMovementprimContact.geom = curContact; |
1149 | _perloopContact.Add(contacts[i]); | 1164 | _perloopContact.Add(curContact); |
1150 | if (m_global_contactcount < maxContactsbeforedeath) | 1165 | if (m_global_contactcount < maxContactsbeforedeath) |
1151 | { | 1166 | { |
1152 | joint = d.JointCreateContact(world, contactgroup, ref AvatarMovementprimContact); | 1167 | joint = d.JointCreateContact(world, contactgroup, ref AvatarMovementprimContact); |
@@ -1156,8 +1171,8 @@ namespace OpenSim.Region.Physics.OdePlugin | |||
1156 | else | 1171 | else |
1157 | { | 1172 | { |
1158 | // Use the non movement contact | 1173 | // Use the non movement contact |
1159 | contact.geom = contacts[i]; | 1174 | contact.geom = curContact; |
1160 | _perloopContact.Add(contacts[i]); | 1175 | _perloopContact.Add(curContact); |
1161 | 1176 | ||
1162 | if (m_global_contactcount < maxContactsbeforedeath) | 1177 | if (m_global_contactcount < maxContactsbeforedeath) |
1163 | { | 1178 | { |
@@ -1175,8 +1190,8 @@ namespace OpenSim.Region.Physics.OdePlugin | |||
1175 | material = ((OdePrim)p2).m_material; | 1190 | material = ((OdePrim)p2).m_material; |
1176 | 1191 | ||
1177 | //m_log.DebugFormat("Material: {0}", material); | 1192 | //m_log.DebugFormat("Material: {0}", material); |
1178 | m_materialContacts[material, 0].geom = contacts[i]; | 1193 | m_materialContacts[material, 0].geom = curContact; |
1179 | _perloopContact.Add(contacts[i]); | 1194 | _perloopContact.Add(curContact); |
1180 | 1195 | ||
1181 | if (m_global_contactcount < maxContactsbeforedeath) | 1196 | if (m_global_contactcount < maxContactsbeforedeath) |
1182 | { | 1197 | { |
@@ -1194,7 +1209,7 @@ namespace OpenSim.Region.Physics.OdePlugin | |||
1194 | } | 1209 | } |
1195 | 1210 | ||
1196 | } | 1211 | } |
1197 | collision_accounting_events(p1, p2, max_collision_depth); | 1212 | collision_accounting_events(p1, p2, maxDepthContact); |
1198 | if (count > geomContactPointsStartthrottle) | 1213 | if (count > geomContactPointsStartthrottle) |
1199 | { | 1214 | { |
1200 | // If there are more then 3 contact points, it's likely | 1215 | // If there are more then 3 contact points, it's likely |
@@ -1278,7 +1293,7 @@ namespace OpenSim.Region.Physics.OdePlugin | |||
1278 | return result; | 1293 | return result; |
1279 | } | 1294 | } |
1280 | 1295 | ||
1281 | private void collision_accounting_events(PhysicsActor p1, PhysicsActor p2, float collisiondepth) | 1296 | private void collision_accounting_events(PhysicsActor p1, PhysicsActor p2, ContactPoint contact) |
1282 | { | 1297 | { |
1283 | // obj1LocalID = 0; | 1298 | // obj1LocalID = 0; |
1284 | //returncollisions = false; | 1299 | //returncollisions = false; |
@@ -1299,7 +1314,7 @@ namespace OpenSim.Region.Physics.OdePlugin | |||
1299 | case ActorTypes.Agent: | 1314 | case ActorTypes.Agent: |
1300 | cc1 = (OdeCharacter)p1; | 1315 | cc1 = (OdeCharacter)p1; |
1301 | obj2LocalID = cc1.m_localID; | 1316 | obj2LocalID = cc1.m_localID; |
1302 | cc1.AddCollisionEvent(cc2.m_localID, collisiondepth); | 1317 | cc1.AddCollisionEvent(cc2.m_localID, contact); |
1303 | //ctype = (int)CollisionCategories.Character; | 1318 | //ctype = (int)CollisionCategories.Character; |
1304 | 1319 | ||
1305 | //if (cc1.CollidingObj) | 1320 | //if (cc1.CollidingObj) |
@@ -1314,7 +1329,7 @@ namespace OpenSim.Region.Physics.OdePlugin | |||
1314 | { | 1329 | { |
1315 | cp1 = (OdePrim) p1; | 1330 | cp1 = (OdePrim) p1; |
1316 | obj2LocalID = cp1.m_localID; | 1331 | obj2LocalID = cp1.m_localID; |
1317 | cp1.AddCollisionEvent(cc2.m_localID, collisiondepth); | 1332 | cp1.AddCollisionEvent(cc2.m_localID, contact); |
1318 | } | 1333 | } |
1319 | //ctype = (int)CollisionCategories.Geom; | 1334 | //ctype = (int)CollisionCategories.Geom; |
1320 | 1335 | ||
@@ -1334,7 +1349,7 @@ namespace OpenSim.Region.Physics.OdePlugin | |||
1334 | break; | 1349 | break; |
1335 | } | 1350 | } |
1336 | 1351 | ||
1337 | cc2.AddCollisionEvent(obj2LocalID, collisiondepth); | 1352 | cc2.AddCollisionEvent(obj2LocalID, contact); |
1338 | break; | 1353 | break; |
1339 | case ActorTypes.Prim: | 1354 | case ActorTypes.Prim: |
1340 | 1355 | ||
@@ -1350,7 +1365,7 @@ namespace OpenSim.Region.Physics.OdePlugin | |||
1350 | { | 1365 | { |
1351 | cc1 = (OdeCharacter) p1; | 1366 | cc1 = (OdeCharacter) p1; |
1352 | obj2LocalID = cc1.m_localID; | 1367 | obj2LocalID = cc1.m_localID; |
1353 | cc1.AddCollisionEvent(cp2.m_localID, collisiondepth); | 1368 | cc1.AddCollisionEvent(cp2.m_localID, contact); |
1354 | //ctype = (int)CollisionCategories.Character; | 1369 | //ctype = (int)CollisionCategories.Character; |
1355 | 1370 | ||
1356 | //if (cc1.CollidingObj) | 1371 | //if (cc1.CollidingObj) |
@@ -1366,7 +1381,7 @@ namespace OpenSim.Region.Physics.OdePlugin | |||
1366 | { | 1381 | { |
1367 | cp1 = (OdePrim) p1; | 1382 | cp1 = (OdePrim) p1; |
1368 | obj2LocalID = cp1.m_localID; | 1383 | obj2LocalID = cp1.m_localID; |
1369 | cp1.AddCollisionEvent(cp2.m_localID, collisiondepth); | 1384 | cp1.AddCollisionEvent(cp2.m_localID, contact); |
1370 | //ctype = (int)CollisionCategories.Geom; | 1385 | //ctype = (int)CollisionCategories.Geom; |
1371 | 1386 | ||
1372 | //if (cp1.CollidingObj) | 1387 | //if (cp1.CollidingObj) |
@@ -1387,7 +1402,7 @@ namespace OpenSim.Region.Physics.OdePlugin | |||
1387 | break; | 1402 | break; |
1388 | } | 1403 | } |
1389 | 1404 | ||
1390 | cp2.AddCollisionEvent(obj2LocalID, collisiondepth); | 1405 | cp2.AddCollisionEvent(obj2LocalID, contact); |
1391 | } | 1406 | } |
1392 | break; | 1407 | break; |
1393 | } | 1408 | } |
@@ -1750,6 +1765,11 @@ namespace OpenSim.Region.Physics.OdePlugin | |||
1750 | return result; | 1765 | return result; |
1751 | } | 1766 | } |
1752 | 1767 | ||
1768 | public override float TimeDilation | ||
1769 | { | ||
1770 | get { return m_timeDilation; } | ||
1771 | } | ||
1772 | |||
1753 | public override bool SupportsNINJAJoints | 1773 | public override bool SupportsNINJAJoints |
1754 | { | 1774 | { |
1755 | get { return m_NINJA_physics_joints_enabled; } | 1775 | get { return m_NINJA_physics_joints_enabled; } |
@@ -2657,8 +2677,10 @@ namespace OpenSim.Region.Physics.OdePlugin | |||
2657 | 2677 | ||
2658 | // Figure out the Frames Per Second we're going at. | 2678 | // Figure out the Frames Per Second we're going at. |
2659 | //(step_time == 0.004f, there's 250 of those per second. Times the step time/step size | 2679 | //(step_time == 0.004f, there's 250 of those per second. Times the step time/step size |
2660 | 2680 | ||
2661 | fps = (step_time/ODE_STEPSIZE) * 1000; | 2681 | fps = (step_time / ODE_STEPSIZE) * 1000; |
2682 | // HACK: Using a time dilation of 1.0 to debug rubberbanding issues | ||
2683 | //m_timeDilation = Math.Min((step_time / ODE_STEPSIZE) / (0.09375f / ODE_STEPSIZE), 1.0f); | ||
2662 | 2684 | ||
2663 | step_time = 0.09375f; | 2685 | step_time = 0.09375f; |
2664 | 2686 | ||