aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/OpenSim/Region/Physics
diff options
context:
space:
mode:
Diffstat (limited to 'OpenSim/Region/Physics')
-rw-r--r--OpenSim/Region/Physics/BasicPhysicsPlugin/BasicPhysicsScene.cs12
-rw-r--r--OpenSim/Region/Physics/BulletSPlugin/BSCharacter.cs451
-rw-r--r--OpenSim/Region/Physics/BulletSPlugin/BSDynamics.cs951
-rw-r--r--OpenSim/Region/Physics/BulletSPlugin/BSPlugin.cs68
-rw-r--r--OpenSim/Region/Physics/BulletSPlugin/BSPrim.cs1357
-rw-r--r--OpenSim/Region/Physics/BulletSPlugin/BSScene.cs860
-rw-r--r--OpenSim/Region/Physics/BulletSPlugin/BulletSimAPI.cs257
-rw-r--r--OpenSim/Region/Physics/ConvexDecompositionDotNet/CTri.cs341
-rw-r--r--OpenSim/Region/Physics/ConvexDecompositionDotNet/Concavity.cs233
-rw-r--r--OpenSim/Region/Physics/ConvexDecompositionDotNet/ConvexBuilder.cs411
-rw-r--r--OpenSim/Region/Physics/ConvexDecompositionDotNet/ConvexDecomposition.cs200
-rw-r--r--OpenSim/Region/Physics/ConvexDecompositionDotNet/ConvexResult.cs74
-rw-r--r--OpenSim/Region/Physics/ConvexDecompositionDotNet/HullClasses.cs171
-rw-r--r--OpenSim/Region/Physics/ConvexDecompositionDotNet/HullTriangle.cs99
-rw-r--r--OpenSim/Region/Physics/ConvexDecompositionDotNet/HullUtils.cs1868
-rw-r--r--OpenSim/Region/Physics/ConvexDecompositionDotNet/LICENSE.txt28
-rw-r--r--OpenSim/Region/Physics/ConvexDecompositionDotNet/Plane.cs99
-rw-r--r--OpenSim/Region/Physics/ConvexDecompositionDotNet/PlaneTri.cs211
-rw-r--r--OpenSim/Region/Physics/ConvexDecompositionDotNet/Properties/AssemblyInfo.cs36
-rw-r--r--OpenSim/Region/Physics/ConvexDecompositionDotNet/Quaternion.cs209
-rw-r--r--OpenSim/Region/Physics/ConvexDecompositionDotNet/README.txt7
-rw-r--r--OpenSim/Region/Physics/ConvexDecompositionDotNet/SplitPlane.cs265
-rw-r--r--OpenSim/Region/Physics/ConvexDecompositionDotNet/VertexLookup.cs70
-rw-r--r--OpenSim/Region/Physics/ConvexDecompositionDotNet/float2.cs70
-rw-r--r--OpenSim/Region/Physics/ConvexDecompositionDotNet/float3.cs444
-rw-r--r--OpenSim/Region/Physics/ConvexDecompositionDotNet/float3x3.cs195
-rw-r--r--OpenSim/Region/Physics/ConvexDecompositionDotNet/float4.cs170
-rw-r--r--OpenSim/Region/Physics/ConvexDecompositionDotNet/float4x4.cs284
-rw-r--r--OpenSim/Region/Physics/ConvexDecompositionDotNet/int3.cs128
-rw-r--r--OpenSim/Region/Physics/ConvexDecompositionDotNet/int4.cs66
-rw-r--r--OpenSim/Region/Physics/Manager/IMesher.cs11
-rwxr-xr-xOpenSim/Region/Physics/Manager/IPhysicsParameters.cs73
-rw-r--r--OpenSim/Region/Physics/Manager/PhysicsScene.cs39
-rw-r--r--OpenSim/Region/Physics/Meshing/Meshmerizer.cs727
-rw-r--r--OpenSim/Region/Physics/OdePlugin/ODECharacter.cs18
-rw-r--r--OpenSim/Region/Physics/OdePlugin/ODEPrim.cs303
-rw-r--r--OpenSim/Region/Physics/OdePlugin/ODERayCastRequestManager.cs92
-rw-r--r--OpenSim/Region/Physics/OdePlugin/OdeScene.cs834
-rw-r--r--OpenSim/Region/Physics/OdePlugin/Tests/ODETestClass.cs5
39 files changed, 10812 insertions, 925 deletions
diff --git a/OpenSim/Region/Physics/BasicPhysicsPlugin/BasicPhysicsScene.cs b/OpenSim/Region/Physics/BasicPhysicsPlugin/BasicPhysicsScene.cs
index 6c9d9ab..1ceed1a 100644
--- a/OpenSim/Region/Physics/BasicPhysicsPlugin/BasicPhysicsScene.cs
+++ b/OpenSim/Region/Physics/BasicPhysicsPlugin/BasicPhysicsScene.cs
@@ -123,11 +123,15 @@ namespace OpenSim.Region.Physics.BasicPhysicsPlugin
123 actorPosition.X = ((int)Constants.RegionSize - 0.1f); 123 actorPosition.X = ((int)Constants.RegionSize - 0.1f);
124 } 124 }
125 125
126 float height = _heightMap[(int)actor.Position.Y * Constants.RegionSize + (int)actor.Position.X] + actor.Size.Z; 126 float terrainHeight = 0;
127 if (_heightMap != null)
128 terrainHeight = _heightMap[(int)actor.Position.Y * Constants.RegionSize + (int)actor.Position.X];
129
130 float height = terrainHeight + actor.Size.Z;
131
127 if (actor.Flying) 132 if (actor.Flying)
128 { 133 {
129 if (actor.Position.Z + (actor.Velocity.Z*timeStep) < 134 if (actor.Position.Z + (actor.Velocity.Z * timeStep) < terrainHeight + 2)
130 _heightMap[(int)actor.Position.Y * Constants.RegionSize + (int)actor.Position.X] + 2)
131 { 135 {
132 actorPosition.Z = height; 136 actorPosition.Z = height;
133 actorVelocity.Z = 0; 137 actorVelocity.Z = 0;
@@ -135,7 +139,7 @@ namespace OpenSim.Region.Physics.BasicPhysicsPlugin
135 } 139 }
136 else 140 else
137 { 141 {
138 actorPosition.Z += actor.Velocity.Z*timeStep; 142 actorPosition.Z += actor.Velocity.Z * timeStep;
139 actor.IsColliding = false; 143 actor.IsColliding = false;
140 } 144 }
141 } 145 }
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSCharacter.cs b/OpenSim/Region/Physics/BulletSPlugin/BSCharacter.cs
new file mode 100644
index 0000000..682eb80
--- /dev/null
+++ b/OpenSim/Region/Physics/BulletSPlugin/BSCharacter.cs
@@ -0,0 +1,451 @@
1/*
2 * Copyright (c) Contributors, http://opensimulator.org/
3 * See CONTRIBUTORS.TXT for a full list of copyright holders.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 * * Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * * Redistributions in binary form must reproduce the above copyrightD
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 * * Neither the name of the OpenSimulator Project nor the
13 * names of its contributors may be used to endorse or promote products
14 * derived from this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
17 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19 * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
20 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
27using System;
28using System.Collections.Generic;
29using System.Reflection;
30using log4net;
31using OpenMetaverse;
32using OpenSim.Framework;
33using OpenSim.Region.Physics.Manager;
34
35namespace OpenSim.Region.Physics.BulletSPlugin
36{
37public class BSCharacter : PhysicsActor
38{
39 private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
40 private static readonly string LogHeader = "[BULLETS CHAR]";
41
42 private BSScene _scene;
43 private String _avName;
44 private bool _stopped;
45 private Vector3 _size;
46 private Vector3 _scale;
47 private PrimitiveBaseShape _pbs;
48 private uint _localID = 0;
49 private bool _grabbed;
50 private bool _selected;
51 private Vector3 _position;
52 private float _mass;
53 public float _density;
54 public float _avatarVolume;
55 private Vector3 _force;
56 private Vector3 _velocity;
57 private Vector3 _torque;
58 private float _collisionScore;
59 private Vector3 _acceleration;
60 private Quaternion _orientation;
61 private int _physicsActorType;
62 private bool _isPhysical;
63 private bool _flying;
64 private bool _setAlwaysRun;
65 private bool _throttleUpdates;
66 private bool _isColliding;
67 private long _collidingStep;
68 private bool _collidingGround;
69 private long _collidingGroundStep;
70 private bool _collidingObj;
71 private bool _floatOnWater;
72 private Vector3 _rotationalVelocity;
73 private bool _kinematic;
74 private float _buoyancy;
75
76 private int _subscribedEventsMs = 0;
77 private int _lastCollisionTime = 0;
78
79 private Vector3 _PIDTarget;
80 private bool _usePID;
81 private float _PIDTau;
82 private bool _useHoverPID;
83 private float _PIDHoverHeight;
84 private PIDHoverType _PIDHoverType;
85 private float _PIDHoverTao;
86
87 public BSCharacter(uint localID, String avName, BSScene parent_scene, Vector3 pos, Vector3 size, bool isFlying)
88 {
89 _localID = localID;
90 _avName = avName;
91 _scene = parent_scene;
92 _position = pos;
93 _size = size;
94 _flying = isFlying;
95 _orientation = Quaternion.Identity;
96 _velocity = Vector3.Zero;
97 _buoyancy = isFlying ? 1f : 0f;
98 _scale = new Vector3(1f, 1f, 1f);
99 _density = _scene.Params.avatarDensity;
100 ComputeAvatarVolumeAndMass(); // set _avatarVolume and _mass based on capsule size, _density and _scale
101
102 ShapeData shapeData = new ShapeData();
103 shapeData.ID = _localID;
104 shapeData.Type = ShapeData.PhysicsShapeType.SHAPE_AVATAR;
105 shapeData.Position = _position;
106 shapeData.Rotation = _orientation;
107 shapeData.Velocity = _velocity;
108 shapeData.Scale = _scale;
109 shapeData.Mass = _mass;
110 shapeData.Buoyancy = _buoyancy;
111 shapeData.Static = ShapeData.numericFalse;
112 shapeData.Friction = _scene.Params.avatarFriction;
113 shapeData.Restitution = _scene.Params.defaultRestitution;
114
115 // do actual create at taint time
116 _scene.TaintedObject(delegate()
117 {
118 BulletSimAPI.CreateObject(parent_scene.WorldID, shapeData);
119 });
120
121 return;
122 }
123
124 // called when this character is being destroyed and the resources should be released
125 public void Destroy()
126 {
127 _scene.TaintedObject(delegate()
128 {
129 BulletSimAPI.DestroyObject(_scene.WorldID, _localID);
130 });
131 }
132
133 public override void RequestPhysicsterseUpdate()
134 {
135 base.RequestPhysicsterseUpdate();
136 }
137
138 public override bool Stopped {
139 get { return _stopped; }
140 }
141 public override Vector3 Size {
142 get { return _size; }
143 set { _size = value;
144 }
145 }
146 public override PrimitiveBaseShape Shape {
147 set { _pbs = value;
148 }
149 }
150 public override uint LocalID {
151 set { _localID = value;
152 }
153 get { return _localID; }
154 }
155 public override bool Grabbed {
156 set { _grabbed = value;
157 }
158 }
159 public override bool Selected {
160 set { _selected = value;
161 }
162 }
163 public override void CrossingFailure() { return; }
164 public override void link(PhysicsActor obj) { return; }
165 public override void delink() { return; }
166 public override void LockAngularMotion(Vector3 axis) { return; }
167
168 public override Vector3 Position {
169 get {
170 // _position = BulletSimAPI.GetObjectPosition(_scene.WorldID, _localID);
171 return _position;
172 }
173 set {
174 _position = value;
175 _scene.TaintedObject(delegate()
176 {
177 BulletSimAPI.SetObjectTranslation(_scene.WorldID, _localID, _position, _orientation);
178 });
179 }
180 }
181 public override float Mass {
182 get {
183 return _mass;
184 }
185 }
186 public override Vector3 Force {
187 get { return _force; }
188 set {
189 _force = value;
190 // m_log.DebugFormat("{0}: Force = {1}", LogHeader, _force);
191 _scene.TaintedObject(delegate()
192 {
193 BulletSimAPI.SetObjectForce(_scene.WorldID, _localID, _force);
194 });
195 }
196 }
197
198 public override int VehicleType {
199 get { return 0; }
200 set { return; }
201 }
202 public override void VehicleFloatParam(int param, float value) { }
203 public override void VehicleVectorParam(int param, Vector3 value) {}
204 public override void VehicleRotationParam(int param, Quaternion rotation) { }
205 public override void VehicleFlags(int param, bool remove) { }
206
207 // Allows the detection of collisions with inherently non-physical prims. see llVolumeDetect for more
208 public override void SetVolumeDetect(int param) { return; }
209
210 public override Vector3 GeometricCenter { get { return Vector3.Zero; } }
211 public override Vector3 CenterOfMass { get { return Vector3.Zero; } }
212 public override Vector3 Velocity {
213 get { return _velocity; }
214 set {
215 _velocity = value;
216 // m_log.DebugFormat("{0}: set velocity = {1}", LogHeader, _velocity);
217 _scene.TaintedObject(delegate()
218 {
219 BulletSimAPI.SetObjectVelocity(_scene.WorldID, _localID, _velocity);
220 });
221 }
222 }
223 public override Vector3 Torque {
224 get { return _torque; }
225 set { _torque = value;
226 }
227 }
228 public override float CollisionScore {
229 get { return _collisionScore; }
230 set { _collisionScore = value;
231 }
232 }
233 public override Vector3 Acceleration {
234 get { return _acceleration; }
235 }
236 public override Quaternion Orientation {
237 get { return _orientation; }
238 set {
239 _orientation = value;
240 // m_log.DebugFormat("{0}: set orientation to {1}", LogHeader, _orientation);
241 _scene.TaintedObject(delegate()
242 {
243 // _position = BulletSimAPI.GetObjectPosition(_scene.WorldID, _localID);
244 BulletSimAPI.SetObjectTranslation(_scene.WorldID, _localID, _position, _orientation);
245 });
246 }
247 }
248 public override int PhysicsActorType {
249 get { return _physicsActorType; }
250 set { _physicsActorType = value;
251 }
252 }
253 public override bool IsPhysical {
254 get { return _isPhysical; }
255 set { _isPhysical = value;
256 }
257 }
258 public override bool Flying {
259 get { return _flying; }
260 set {
261 _flying = value;
262 _scene.TaintedObject(delegate()
263 {
264 // simulate flying by changing the effect of gravity
265 BulletSimAPI.SetObjectBuoyancy(_scene.WorldID, LocalID, _flying ? 1f : 0f);
266 });
267 }
268 }
269 public override bool
270 SetAlwaysRun {
271 get { return _setAlwaysRun; }
272 set { _setAlwaysRun = value; }
273 }
274 public override bool ThrottleUpdates {
275 get { return _throttleUpdates; }
276 set { _throttleUpdates = value; }
277 }
278 public override bool IsColliding {
279 get { return (_collidingStep == _scene.SimulationStep); }
280 set { _isColliding = value; }
281 }
282 public override bool CollidingGround {
283 get { return (_collidingGroundStep == _scene.SimulationStep); }
284 set { _collidingGround = value; }
285 }
286 public override bool CollidingObj {
287 get { return _collidingObj; }
288 set { _collidingObj = value; }
289 }
290 public override bool FloatOnWater {
291 set { _floatOnWater = value; }
292 }
293 public override Vector3 RotationalVelocity {
294 get { return _rotationalVelocity; }
295 set { _rotationalVelocity = value; }
296 }
297 public override bool Kinematic {
298 get { return _kinematic; }
299 set { _kinematic = value; }
300 }
301 public override float Buoyancy {
302 get { return _buoyancy; }
303 set { _buoyancy = value;
304 _scene.TaintedObject(delegate()
305 {
306 BulletSimAPI.SetObjectBuoyancy(_scene.WorldID, LocalID, _buoyancy);
307 });
308 }
309 }
310
311 // Used for MoveTo
312 public override Vector3 PIDTarget {
313 set { _PIDTarget = value; }
314 }
315 public override bool PIDActive {
316 set { _usePID = value; }
317 }
318 public override float PIDTau {
319 set { _PIDTau = value; }
320 }
321
322 // Used for llSetHoverHeight and maybe vehicle height
323 // Hover Height will override MoveTo target's Z
324 public override bool PIDHoverActive {
325 set { _useHoverPID = value; }
326 }
327 public override float PIDHoverHeight {
328 set { _PIDHoverHeight = value; }
329 }
330 public override PIDHoverType PIDHoverType {
331 set { _PIDHoverType = value; }
332 }
333 public override float PIDHoverTau {
334 set { _PIDHoverTao = value; }
335 }
336
337 // For RotLookAt
338 public override Quaternion APIDTarget { set { return; } }
339 public override bool APIDActive { set { return; } }
340 public override float APIDStrength { set { return; } }
341 public override float APIDDamping { set { return; } }
342
343 public override void AddForce(Vector3 force, bool pushforce) {
344 if (force.IsFinite())
345 {
346 _force.X += force.X;
347 _force.Y += force.Y;
348 _force.Z += force.Z;
349 // m_log.DebugFormat("{0}: AddForce. adding={1}, newForce={2}", LogHeader, force, _force);
350 _scene.TaintedObject(delegate()
351 {
352 BulletSimAPI.SetObjectForce(_scene.WorldID, _localID, _force);
353 });
354 }
355 else
356 {
357 m_log.WarnFormat("{0}: Got a NaN force applied to a Character", LogHeader);
358 }
359 //m_lastUpdateSent = false;
360 }
361 public override void AddAngularForce(Vector3 force, bool pushforce) {
362 }
363 public override void SetMomentum(Vector3 momentum) {
364 }
365 public override void SubscribeEvents(int ms) {
366 _subscribedEventsMs = ms;
367 _lastCollisionTime = Util.EnvironmentTickCount() - _subscribedEventsMs; // make first collision happen
368 }
369 public override void UnSubscribeEvents() {
370 _subscribedEventsMs = 0;
371 }
372 public override bool SubscribedEvents() {
373 return (_subscribedEventsMs > 0);
374 }
375
376 // set _avatarVolume and _mass based on capsule size, _density and _scale
377 private void ComputeAvatarVolumeAndMass()
378 {
379 _avatarVolume = (float)(
380 Math.PI
381 * _scene.Params.avatarCapsuleRadius * _scale.X
382 * _scene.Params.avatarCapsuleRadius * _scale.Y
383 * _scene.Params.avatarCapsuleHeight * _scale.Z);
384 _mass = _density * _avatarVolume;
385 }
386
387 // The physics engine says that properties have updated. Update same and inform
388 // the world that things have changed.
389 public void UpdateProperties(EntityProperties entprop)
390 {
391 bool changed = false;
392 // we assign to the local variables so the normal set action does not happen
393 if (_position != entprop.Position)
394 {
395 _position = entprop.Position;
396 changed = true;
397 }
398 if (_orientation != entprop.Rotation)
399 {
400 _orientation = entprop.Rotation;
401 changed = true;
402 }
403 if (_velocity != entprop.Velocity)
404 {
405 _velocity = entprop.Velocity;
406 changed = true;
407 }
408 if (_acceleration != entprop.Acceleration)
409 {
410 _acceleration = entprop.Acceleration;
411 changed = true;
412 }
413 if (_rotationalVelocity != entprop.RotationalVelocity)
414 {
415 _rotationalVelocity = entprop.RotationalVelocity;
416 changed = true;
417 }
418 if (changed)
419 {
420 // m_log.DebugFormat("{0}: UpdateProperties: id={1}, c={2}, pos={3}, rot={4}", LogHeader, LocalID, changed, _position, _orientation);
421 // Avatar movement is not done by generating this event. There is a system that
422 // checks for avatar updates each heartbeat loop.
423 // base.RequestPhysicsterseUpdate();
424 }
425 }
426
427 public void Collide(uint collidingWith, ActorTypes type, Vector3 contactPoint, Vector3 contactNormal, float pentrationDepth)
428 {
429 // m_log.DebugFormat("{0}: Collide: ms={1}, id={2}, with={3}", LogHeader, _subscribedEventsMs, LocalID, collidingWith);
430
431 // The following makes IsColliding() and IsCollidingGround() work
432 _collidingStep = _scene.SimulationStep;
433 if (collidingWith == BSScene.TERRAIN_ID || collidingWith == BSScene.GROUNDPLANE_ID)
434 {
435 _collidingGroundStep = _scene.SimulationStep;
436 }
437
438 // throttle collisions to the rate specified in the subscription
439 if (_subscribedEventsMs == 0) return; // don't want collisions
440 int nowTime = _scene.SimulationNowTime;
441 if (nowTime < (_lastCollisionTime + _subscribedEventsMs)) return;
442 _lastCollisionTime = nowTime;
443
444 Dictionary<uint, ContactPoint> contactPoints = new Dictionary<uint, ContactPoint>();
445 contactPoints.Add(collidingWith, new ContactPoint(contactPoint, contactNormal, pentrationDepth));
446 CollisionEventUpdate args = new CollisionEventUpdate(LocalID, (int)type, 1, contactPoints);
447 base.SendCollisionUpdate(args);
448 }
449
450}
451}
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSDynamics.cs b/OpenSim/Region/Physics/BulletSPlugin/BSDynamics.cs
new file mode 100644
index 0000000..046726d
--- /dev/null
+++ b/OpenSim/Region/Physics/BulletSPlugin/BSDynamics.cs
@@ -0,0 +1,951 @@
1/*
2 * Copyright (c) Contributors, http://opensimulator.org/
3 * See CONTRIBUTORS.TXT for a full list of copyright holders.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 * * Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * * Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 * * Neither the name of the OpenSimulator Project nor the
13 * names of its contributors may be used to endorse or promote products
14 * derived from this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
17 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19 * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
20 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
27
28/* RA: June 14, 2011. Copied from ODEDynamics.cs and converted to
29 * call the BulletSim system.
30 */
31/* Revised Aug, Sept 2009 by Kitto Flora. ODEDynamics.cs replaces
32 * ODEVehicleSettings.cs. It and ODEPrim.cs are re-organised:
33 * ODEPrim.cs contains methods dealing with Prim editing, Prim
34 * characteristics and Kinetic motion.
35 * ODEDynamics.cs contains methods dealing with Prim Physical motion
36 * (dynamics) and the associated settings. Old Linear and angular
37 * motors for dynamic motion have been replace with MoveLinear()
38 * and MoveAngular(); 'Physical' is used only to switch ODE dynamic
39 * simualtion on/off; VEHICAL_TYPE_NONE/VEHICAL_TYPE_<other> is to
40 * switch between 'VEHICLE' parameter use and general dynamics
41 * settings use.
42 */
43
44using System;
45using System.Collections.Generic;
46using System.Reflection;
47using System.Runtime.InteropServices;
48using log4net;
49using OpenMetaverse;
50using OpenSim.Framework;
51using OpenSim.Region.Physics.Manager;
52
53namespace OpenSim.Region.Physics.BulletSPlugin
54{
55 public class BSDynamics
56 {
57 private int frcount = 0; // Used to limit dynamics debug output to
58 // every 100th frame
59
60 // private BSScene m_parentScene = null;
61 private BSPrim m_prim; // the prim this dynamic controller belongs to
62
63 // Vehicle properties
64 private Vehicle m_type = Vehicle.TYPE_NONE; // If a 'VEHICLE', and what kind
65 public Vehicle Type
66 {
67 get { return m_type; }
68 }
69 // private Quaternion m_referenceFrame = Quaternion.Identity; // Axis modifier
70 private VehicleFlag m_flags = (VehicleFlag) 0; // Boolean settings:
71 // HOVER_TERRAIN_ONLY
72 // HOVER_GLOBAL_HEIGHT
73 // NO_DEFLECTION_UP
74 // HOVER_WATER_ONLY
75 // HOVER_UP_ONLY
76 // LIMIT_MOTOR_UP
77 // LIMIT_ROLL_ONLY
78 private VehicleFlag m_Hoverflags = (VehicleFlag)0;
79 private Vector3 m_BlockingEndPoint = Vector3.Zero;
80 private Quaternion m_RollreferenceFrame = Quaternion.Identity;
81 // Linear properties
82 private Vector3 m_linearMotorDirection = Vector3.Zero; // velocity requested by LSL, decayed by time
83 private Vector3 m_linearMotorDirectionLASTSET = Vector3.Zero; // velocity requested by LSL
84 private Vector3 m_dir = Vector3.Zero; // velocity applied to body
85 private Vector3 m_linearFrictionTimescale = Vector3.Zero;
86 private float m_linearMotorDecayTimescale = 0;
87 private float m_linearMotorTimescale = 0;
88 private Vector3 m_lastLinearVelocityVector = Vector3.Zero;
89 private Vector3 m_lastPositionVector = Vector3.Zero;
90 // private bool m_LinearMotorSetLastFrame = false;
91 // private Vector3 m_linearMotorOffset = Vector3.Zero;
92
93 //Angular properties
94 private Vector3 m_angularMotorDirection = Vector3.Zero; // angular velocity requested by LSL motor
95 private int m_angularMotorApply = 0; // application frame counter
96 private Vector3 m_angularMotorVelocity = Vector3.Zero; // current angular motor velocity
97 private float m_angularMotorTimescale = 0; // motor angular velocity ramp up rate
98 private float m_angularMotorDecayTimescale = 0; // motor angular velocity decay rate
99 private Vector3 m_angularFrictionTimescale = Vector3.Zero; // body angular velocity decay rate
100 private Vector3 m_lastAngularVelocity = Vector3.Zero; // what was last applied to body
101 // private Vector3 m_lastVertAttractor = Vector3.Zero; // what VA was last applied to body
102
103 //Deflection properties
104 // private float m_angularDeflectionEfficiency = 0;
105 // private float m_angularDeflectionTimescale = 0;
106 // private float m_linearDeflectionEfficiency = 0;
107 // private float m_linearDeflectionTimescale = 0;
108
109 //Banking properties
110 // private float m_bankingEfficiency = 0;
111 // private float m_bankingMix = 0;
112 // private float m_bankingTimescale = 0;
113
114 //Hover and Buoyancy properties
115 private float m_VhoverHeight = 0f;
116// private float m_VhoverEfficiency = 0f;
117 private float m_VhoverTimescale = 0f;
118 private float m_VhoverTargetHeight = -1.0f; // if <0 then no hover, else its the current target height
119 private float m_VehicleBuoyancy = 0f; //KF: m_VehicleBuoyancy is set by VEHICLE_BUOYANCY for a vehicle.
120 // Modifies gravity. Slider between -1 (double-gravity) and 1 (full anti-gravity)
121 // KF: So far I have found no good method to combine a script-requested .Z velocity and gravity.
122 // Therefore only m_VehicleBuoyancy=1 (0g) will use the script-requested .Z velocity.
123
124 //Attractor properties
125 private float m_verticalAttractionEfficiency = 1.0f; // damped
126 private float m_verticalAttractionTimescale = 500f; // Timescale > 300 means no vert attractor.
127
128 public BSDynamics(BSPrim myPrim)
129 {
130 m_prim = myPrim;
131 m_type = Vehicle.TYPE_NONE;
132 }
133
134 internal void ProcessFloatVehicleParam(Vehicle pParam, float pValue)
135 {
136 switch (pParam)
137 {
138 case Vehicle.ANGULAR_DEFLECTION_EFFICIENCY:
139 if (pValue < 0.01f) pValue = 0.01f;
140 // m_angularDeflectionEfficiency = pValue;
141 break;
142 case Vehicle.ANGULAR_DEFLECTION_TIMESCALE:
143 if (pValue < 0.01f) pValue = 0.01f;
144 // m_angularDeflectionTimescale = pValue;
145 break;
146 case Vehicle.ANGULAR_MOTOR_DECAY_TIMESCALE:
147 if (pValue < 0.01f) pValue = 0.01f;
148 m_angularMotorDecayTimescale = pValue;
149 break;
150 case Vehicle.ANGULAR_MOTOR_TIMESCALE:
151 if (pValue < 0.01f) pValue = 0.01f;
152 m_angularMotorTimescale = pValue;
153 break;
154 case Vehicle.BANKING_EFFICIENCY:
155 if (pValue < 0.01f) pValue = 0.01f;
156 // m_bankingEfficiency = pValue;
157 break;
158 case Vehicle.BANKING_MIX:
159 if (pValue < 0.01f) pValue = 0.01f;
160 // m_bankingMix = pValue;
161 break;
162 case Vehicle.BANKING_TIMESCALE:
163 if (pValue < 0.01f) pValue = 0.01f;
164 // m_bankingTimescale = pValue;
165 break;
166 case Vehicle.BUOYANCY:
167 if (pValue < -1f) pValue = -1f;
168 if (pValue > 1f) pValue = 1f;
169 m_VehicleBuoyancy = pValue;
170 break;
171// case Vehicle.HOVER_EFFICIENCY:
172// if (pValue < 0f) pValue = 0f;
173// if (pValue > 1f) pValue = 1f;
174// m_VhoverEfficiency = pValue;
175// break;
176 case Vehicle.HOVER_HEIGHT:
177 m_VhoverHeight = pValue;
178 break;
179 case Vehicle.HOVER_TIMESCALE:
180 if (pValue < 0.01f) pValue = 0.01f;
181 m_VhoverTimescale = pValue;
182 break;
183 case Vehicle.LINEAR_DEFLECTION_EFFICIENCY:
184 if (pValue < 0.01f) pValue = 0.01f;
185 // m_linearDeflectionEfficiency = pValue;
186 break;
187 case Vehicle.LINEAR_DEFLECTION_TIMESCALE:
188 if (pValue < 0.01f) pValue = 0.01f;
189 // m_linearDeflectionTimescale = pValue;
190 break;
191 case Vehicle.LINEAR_MOTOR_DECAY_TIMESCALE:
192 if (pValue < 0.01f) pValue = 0.01f;
193 m_linearMotorDecayTimescale = pValue;
194 break;
195 case Vehicle.LINEAR_MOTOR_TIMESCALE:
196 if (pValue < 0.01f) pValue = 0.01f;
197 m_linearMotorTimescale = pValue;
198 break;
199 case Vehicle.VERTICAL_ATTRACTION_EFFICIENCY:
200 if (pValue < 0.1f) pValue = 0.1f; // Less goes unstable
201 if (pValue > 1.0f) pValue = 1.0f;
202 m_verticalAttractionEfficiency = pValue;
203 break;
204 case Vehicle.VERTICAL_ATTRACTION_TIMESCALE:
205 if (pValue < 0.01f) pValue = 0.01f;
206 m_verticalAttractionTimescale = pValue;
207 break;
208
209 // These are vector properties but the engine lets you use a single float value to
210 // set all of the components to the same value
211 case Vehicle.ANGULAR_FRICTION_TIMESCALE:
212 m_angularFrictionTimescale = new Vector3(pValue, pValue, pValue);
213 break;
214 case Vehicle.ANGULAR_MOTOR_DIRECTION:
215 m_angularMotorDirection = new Vector3(pValue, pValue, pValue);
216 m_angularMotorApply = 10;
217 break;
218 case Vehicle.LINEAR_FRICTION_TIMESCALE:
219 m_linearFrictionTimescale = new Vector3(pValue, pValue, pValue);
220 break;
221 case Vehicle.LINEAR_MOTOR_DIRECTION:
222 m_linearMotorDirection = new Vector3(pValue, pValue, pValue);
223 m_linearMotorDirectionLASTSET = new Vector3(pValue, pValue, pValue);
224 break;
225 case Vehicle.LINEAR_MOTOR_OFFSET:
226 // m_linearMotorOffset = new Vector3(pValue, pValue, pValue);
227 break;
228
229 }
230 }//end ProcessFloatVehicleParam
231
232 internal void ProcessVectorVehicleParam(Vehicle pParam, Vector3 pValue)
233 {
234 switch (pParam)
235 {
236 case Vehicle.ANGULAR_FRICTION_TIMESCALE:
237 m_angularFrictionTimescale = new Vector3(pValue.X, pValue.Y, pValue.Z);
238 break;
239 case Vehicle.ANGULAR_MOTOR_DIRECTION:
240 m_angularMotorDirection = new Vector3(pValue.X, pValue.Y, pValue.Z);
241 // Limit requested angular speed to 2 rps= 4 pi rads/sec
242 if (m_angularMotorDirection.X > 12.56f) m_angularMotorDirection.X = 12.56f;
243 if (m_angularMotorDirection.X < - 12.56f) m_angularMotorDirection.X = - 12.56f;
244 if (m_angularMotorDirection.Y > 12.56f) m_angularMotorDirection.Y = 12.56f;
245 if (m_angularMotorDirection.Y < - 12.56f) m_angularMotorDirection.Y = - 12.56f;
246 if (m_angularMotorDirection.Z > 12.56f) m_angularMotorDirection.Z = 12.56f;
247 if (m_angularMotorDirection.Z < - 12.56f) m_angularMotorDirection.Z = - 12.56f;
248 m_angularMotorApply = 10;
249 break;
250 case Vehicle.LINEAR_FRICTION_TIMESCALE:
251 m_linearFrictionTimescale = new Vector3(pValue.X, pValue.Y, pValue.Z);
252 break;
253 case Vehicle.LINEAR_MOTOR_DIRECTION:
254 m_linearMotorDirection = new Vector3(pValue.X, pValue.Y, pValue.Z);
255 m_linearMotorDirectionLASTSET = new Vector3(pValue.X, pValue.Y, pValue.Z);
256 break;
257 case Vehicle.LINEAR_MOTOR_OFFSET:
258 // m_linearMotorOffset = new Vector3(pValue.X, pValue.Y, pValue.Z);
259 break;
260 case Vehicle.BLOCK_EXIT:
261 m_BlockingEndPoint = new Vector3(pValue.X, pValue.Y, pValue.Z);
262 break;
263 }
264 }//end ProcessVectorVehicleParam
265
266 internal void ProcessRotationVehicleParam(Vehicle pParam, Quaternion pValue)
267 {
268 switch (pParam)
269 {
270 case Vehicle.REFERENCE_FRAME:
271 // m_referenceFrame = pValue;
272 break;
273 case Vehicle.ROLL_FRAME:
274 m_RollreferenceFrame = pValue;
275 break;
276 }
277 }//end ProcessRotationVehicleParam
278
279 internal void ProcessVehicleFlags(int pParam, bool remove)
280 {
281 if (remove)
282 {
283 if (pParam == -1)
284 {
285 m_flags = (VehicleFlag)0;
286 m_Hoverflags = (VehicleFlag)0;
287 return;
288 }
289 if ((pParam & (int)VehicleFlag.HOVER_GLOBAL_HEIGHT) == (int)VehicleFlag.HOVER_GLOBAL_HEIGHT)
290 {
291 if ((m_Hoverflags & VehicleFlag.HOVER_GLOBAL_HEIGHT) != (VehicleFlag)0)
292 m_Hoverflags &= ~(VehicleFlag.HOVER_GLOBAL_HEIGHT);
293 }
294 if ((pParam & (int)VehicleFlag.HOVER_TERRAIN_ONLY) == (int)VehicleFlag.HOVER_TERRAIN_ONLY)
295 {
296 if ((m_Hoverflags & VehicleFlag.HOVER_TERRAIN_ONLY) != (VehicleFlag)0)
297 m_Hoverflags &= ~(VehicleFlag.HOVER_TERRAIN_ONLY);
298 }
299 if ((pParam & (int)VehicleFlag.HOVER_UP_ONLY) == (int)VehicleFlag.HOVER_UP_ONLY)
300 {
301 if ((m_Hoverflags & VehicleFlag.HOVER_UP_ONLY) != (VehicleFlag)0)
302 m_Hoverflags &= ~(VehicleFlag.HOVER_UP_ONLY);
303 }
304 if ((pParam & (int)VehicleFlag.HOVER_WATER_ONLY) == (int)VehicleFlag.HOVER_WATER_ONLY)
305 {
306 if ((m_Hoverflags & VehicleFlag.HOVER_WATER_ONLY) != (VehicleFlag)0)
307 m_Hoverflags &= ~(VehicleFlag.HOVER_WATER_ONLY);
308 }
309 if ((pParam & (int)VehicleFlag.LIMIT_MOTOR_UP) == (int)VehicleFlag.LIMIT_MOTOR_UP)
310 {
311 if ((m_flags & VehicleFlag.LIMIT_MOTOR_UP) != (VehicleFlag)0)
312 m_flags &= ~(VehicleFlag.LIMIT_MOTOR_UP);
313 }
314 if ((pParam & (int)VehicleFlag.LIMIT_ROLL_ONLY) == (int)VehicleFlag.LIMIT_ROLL_ONLY)
315 {
316 if ((m_flags & VehicleFlag.LIMIT_ROLL_ONLY) != (VehicleFlag)0)
317 m_flags &= ~(VehicleFlag.LIMIT_ROLL_ONLY);
318 }
319 if ((pParam & (int)VehicleFlag.MOUSELOOK_BANK) == (int)VehicleFlag.MOUSELOOK_BANK)
320 {
321 if ((m_flags & VehicleFlag.MOUSELOOK_BANK) != (VehicleFlag)0)
322 m_flags &= ~(VehicleFlag.MOUSELOOK_BANK);
323 }
324 if ((pParam & (int)VehicleFlag.MOUSELOOK_STEER) == (int)VehicleFlag.MOUSELOOK_STEER)
325 {
326 if ((m_flags & VehicleFlag.MOUSELOOK_STEER) != (VehicleFlag)0)
327 m_flags &= ~(VehicleFlag.MOUSELOOK_STEER);
328 }
329 if ((pParam & (int)VehicleFlag.NO_DEFLECTION_UP) == (int)VehicleFlag.NO_DEFLECTION_UP)
330 {
331 if ((m_flags & VehicleFlag.NO_DEFLECTION_UP) != (VehicleFlag)0)
332 m_flags &= ~(VehicleFlag.NO_DEFLECTION_UP);
333 }
334 if ((pParam & (int)VehicleFlag.CAMERA_DECOUPLED) == (int)VehicleFlag.CAMERA_DECOUPLED)
335 {
336 if ((m_flags & VehicleFlag.CAMERA_DECOUPLED) != (VehicleFlag)0)
337 m_flags &= ~(VehicleFlag.CAMERA_DECOUPLED);
338 }
339 if ((pParam & (int)VehicleFlag.NO_X) == (int)VehicleFlag.NO_X)
340 {
341 if ((m_flags & VehicleFlag.NO_X) != (VehicleFlag)0)
342 m_flags &= ~(VehicleFlag.NO_X);
343 }
344 if ((pParam & (int)VehicleFlag.NO_Y) == (int)VehicleFlag.NO_Y)
345 {
346 if ((m_flags & VehicleFlag.NO_Y) != (VehicleFlag)0)
347 m_flags &= ~(VehicleFlag.NO_Y);
348 }
349 if ((pParam & (int)VehicleFlag.NO_Z) == (int)VehicleFlag.NO_Z)
350 {
351 if ((m_flags & VehicleFlag.NO_Z) != (VehicleFlag)0)
352 m_flags &= ~(VehicleFlag.NO_Z);
353 }
354 if ((pParam & (int)VehicleFlag.LOCK_HOVER_HEIGHT) == (int)VehicleFlag.LOCK_HOVER_HEIGHT)
355 {
356 if ((m_Hoverflags & VehicleFlag.LOCK_HOVER_HEIGHT) != (VehicleFlag)0)
357 m_Hoverflags &= ~(VehicleFlag.LOCK_HOVER_HEIGHT);
358 }
359 if ((pParam & (int)VehicleFlag.NO_DEFLECTION) == (int)VehicleFlag.NO_DEFLECTION)
360 {
361 if ((m_flags & VehicleFlag.NO_DEFLECTION) != (VehicleFlag)0)
362 m_flags &= ~(VehicleFlag.NO_DEFLECTION);
363 }
364 if ((pParam & (int)VehicleFlag.LOCK_ROTATION) == (int)VehicleFlag.LOCK_ROTATION)
365 {
366 if ((m_flags & VehicleFlag.LOCK_ROTATION) != (VehicleFlag)0)
367 m_flags &= ~(VehicleFlag.LOCK_ROTATION);
368 }
369 }
370 else
371 {
372 if ((pParam & (int)VehicleFlag.HOVER_GLOBAL_HEIGHT) == (int)VehicleFlag.HOVER_GLOBAL_HEIGHT)
373 {
374 m_Hoverflags |= (VehicleFlag.HOVER_GLOBAL_HEIGHT | m_flags);
375 }
376 if ((pParam & (int)VehicleFlag.HOVER_TERRAIN_ONLY) == (int)VehicleFlag.HOVER_TERRAIN_ONLY)
377 {
378 m_Hoverflags |= (VehicleFlag.HOVER_TERRAIN_ONLY | m_flags);
379 }
380 if ((pParam & (int)VehicleFlag.HOVER_UP_ONLY) == (int)VehicleFlag.HOVER_UP_ONLY)
381 {
382 m_Hoverflags |= (VehicleFlag.HOVER_UP_ONLY | m_flags);
383 }
384 if ((pParam & (int)VehicleFlag.HOVER_WATER_ONLY) == (int)VehicleFlag.HOVER_WATER_ONLY)
385 {
386 m_Hoverflags |= (VehicleFlag.HOVER_WATER_ONLY | m_flags);
387 }
388 if ((pParam & (int)VehicleFlag.LIMIT_MOTOR_UP) == (int)VehicleFlag.LIMIT_MOTOR_UP)
389 {
390 m_flags |= (VehicleFlag.LIMIT_MOTOR_UP | m_flags);
391 }
392 if ((pParam & (int)VehicleFlag.MOUSELOOK_BANK) == (int)VehicleFlag.MOUSELOOK_BANK)
393 {
394 m_flags |= (VehicleFlag.MOUSELOOK_BANK | m_flags);
395 }
396 if ((pParam & (int)VehicleFlag.MOUSELOOK_STEER) == (int)VehicleFlag.MOUSELOOK_STEER)
397 {
398 m_flags |= (VehicleFlag.MOUSELOOK_STEER | m_flags);
399 }
400 if ((pParam & (int)VehicleFlag.NO_DEFLECTION_UP) == (int)VehicleFlag.NO_DEFLECTION_UP)
401 {
402 m_flags |= (VehicleFlag.NO_DEFLECTION_UP | m_flags);
403 }
404 if ((pParam & (int)VehicleFlag.CAMERA_DECOUPLED) == (int)VehicleFlag.CAMERA_DECOUPLED)
405 {
406 m_flags |= (VehicleFlag.CAMERA_DECOUPLED | m_flags);
407 }
408 if ((pParam & (int)VehicleFlag.NO_X) == (int)VehicleFlag.NO_X)
409 {
410 m_flags |= (VehicleFlag.NO_X);
411 }
412 if ((pParam & (int)VehicleFlag.NO_Y) == (int)VehicleFlag.NO_Y)
413 {
414 m_flags |= (VehicleFlag.NO_Y);
415 }
416 if ((pParam & (int)VehicleFlag.NO_Z) == (int)VehicleFlag.NO_Z)
417 {
418 m_flags |= (VehicleFlag.NO_Z);
419 }
420 if ((pParam & (int)VehicleFlag.LOCK_HOVER_HEIGHT) == (int)VehicleFlag.LOCK_HOVER_HEIGHT)
421 {
422 m_Hoverflags |= (VehicleFlag.LOCK_HOVER_HEIGHT);
423 }
424 if ((pParam & (int)VehicleFlag.NO_DEFLECTION) == (int)VehicleFlag.NO_DEFLECTION)
425 {
426 m_flags |= (VehicleFlag.NO_DEFLECTION);
427 }
428 if ((pParam & (int)VehicleFlag.LOCK_ROTATION) == (int)VehicleFlag.LOCK_ROTATION)
429 {
430 m_flags |= (VehicleFlag.LOCK_ROTATION);
431 }
432 }
433 }//end ProcessVehicleFlags
434
435 internal void ProcessTypeChange(Vehicle pType)
436 {
437 // Set Defaults For Type
438 m_type = pType;
439 switch (pType)
440 {
441 case Vehicle.TYPE_NONE:
442 m_linearFrictionTimescale = new Vector3(0, 0, 0);
443 m_angularFrictionTimescale = new Vector3(0, 0, 0);
444 m_linearMotorDirection = Vector3.Zero;
445 m_linearMotorTimescale = 0;
446 m_linearMotorDecayTimescale = 0;
447 m_angularMotorDirection = Vector3.Zero;
448 m_angularMotorTimescale = 0;
449 m_angularMotorDecayTimescale = 0;
450 m_VhoverHeight = 0;
451 m_VhoverTimescale = 0;
452 m_VehicleBuoyancy = 0;
453 m_flags = (VehicleFlag)0;
454 break;
455
456 case Vehicle.TYPE_SLED:
457 m_linearFrictionTimescale = new Vector3(30, 1, 1000);
458 m_angularFrictionTimescale = new Vector3(1000, 1000, 1000);
459 m_linearMotorDirection = Vector3.Zero;
460 m_linearMotorTimescale = 1000;
461 m_linearMotorDecayTimescale = 120;
462 m_angularMotorDirection = Vector3.Zero;
463 m_angularMotorTimescale = 1000;
464 m_angularMotorDecayTimescale = 120;
465 m_VhoverHeight = 0;
466// m_VhoverEfficiency = 1;
467 m_VhoverTimescale = 10;
468 m_VehicleBuoyancy = 0;
469 // m_linearDeflectionEfficiency = 1;
470 // m_linearDeflectionTimescale = 1;
471 // m_angularDeflectionEfficiency = 1;
472 // m_angularDeflectionTimescale = 1000;
473 // m_bankingEfficiency = 0;
474 // m_bankingMix = 1;
475 // m_bankingTimescale = 10;
476 // m_referenceFrame = Quaternion.Identity;
477 m_Hoverflags &=
478 ~(VehicleFlag.HOVER_WATER_ONLY | VehicleFlag.HOVER_TERRAIN_ONLY |
479 VehicleFlag.HOVER_GLOBAL_HEIGHT | VehicleFlag.HOVER_UP_ONLY);
480 m_flags |= (VehicleFlag.NO_DEFLECTION_UP | VehicleFlag.LIMIT_ROLL_ONLY | VehicleFlag.LIMIT_MOTOR_UP);
481 break;
482 case Vehicle.TYPE_CAR:
483 m_linearFrictionTimescale = new Vector3(100, 2, 1000);
484 m_angularFrictionTimescale = new Vector3(1000, 1000, 1000);
485 m_linearMotorDirection = Vector3.Zero;
486 m_linearMotorTimescale = 1;
487 m_linearMotorDecayTimescale = 60;
488 m_angularMotorDirection = Vector3.Zero;
489 m_angularMotorTimescale = 1;
490 m_angularMotorDecayTimescale = 0.8f;
491 m_VhoverHeight = 0;
492// m_VhoverEfficiency = 0;
493 m_VhoverTimescale = 1000;
494 m_VehicleBuoyancy = 0;
495 // // m_linearDeflectionEfficiency = 1;
496 // // m_linearDeflectionTimescale = 2;
497 // // m_angularDeflectionEfficiency = 0;
498 // m_angularDeflectionTimescale = 10;
499 m_verticalAttractionEfficiency = 1f;
500 m_verticalAttractionTimescale = 10f;
501 // m_bankingEfficiency = -0.2f;
502 // m_bankingMix = 1;
503 // m_bankingTimescale = 1;
504 // m_referenceFrame = Quaternion.Identity;
505 m_Hoverflags &= ~(VehicleFlag.HOVER_WATER_ONLY | VehicleFlag.HOVER_TERRAIN_ONLY | VehicleFlag.HOVER_GLOBAL_HEIGHT);
506 m_flags |= (VehicleFlag.NO_DEFLECTION_UP | VehicleFlag.LIMIT_ROLL_ONLY |
507 VehicleFlag.LIMIT_MOTOR_UP);
508 m_Hoverflags |= (VehicleFlag.HOVER_UP_ONLY);
509 break;
510 case Vehicle.TYPE_BOAT:
511 m_linearFrictionTimescale = new Vector3(10, 3, 2);
512 m_angularFrictionTimescale = new Vector3(10,10,10);
513 m_linearMotorDirection = Vector3.Zero;
514 m_linearMotorTimescale = 5;
515 m_linearMotorDecayTimescale = 60;
516 m_angularMotorDirection = Vector3.Zero;
517 m_angularMotorTimescale = 4;
518 m_angularMotorDecayTimescale = 4;
519 m_VhoverHeight = 0;
520// m_VhoverEfficiency = 0.5f;
521 m_VhoverTimescale = 2;
522 m_VehicleBuoyancy = 1;
523 // m_linearDeflectionEfficiency = 0.5f;
524 // m_linearDeflectionTimescale = 3;
525 // m_angularDeflectionEfficiency = 0.5f;
526 // m_angularDeflectionTimescale = 5;
527 m_verticalAttractionEfficiency = 0.5f;
528 m_verticalAttractionTimescale = 5f;
529 // m_bankingEfficiency = -0.3f;
530 // m_bankingMix = 0.8f;
531 // m_bankingTimescale = 1;
532 // m_referenceFrame = Quaternion.Identity;
533 m_Hoverflags &= ~(VehicleFlag.HOVER_TERRAIN_ONLY |
534 VehicleFlag.HOVER_GLOBAL_HEIGHT | VehicleFlag.HOVER_UP_ONLY);
535 m_flags &= ~(VehicleFlag.LIMIT_ROLL_ONLY);
536 m_flags |= (VehicleFlag.NO_DEFLECTION_UP |
537 VehicleFlag.LIMIT_MOTOR_UP);
538 m_Hoverflags |= (VehicleFlag.HOVER_WATER_ONLY);
539 break;
540 case Vehicle.TYPE_AIRPLANE:
541 m_linearFrictionTimescale = new Vector3(200, 10, 5);
542 m_angularFrictionTimescale = new Vector3(20, 20, 20);
543 m_linearMotorDirection = Vector3.Zero;
544 m_linearMotorTimescale = 2;
545 m_linearMotorDecayTimescale = 60;
546 m_angularMotorDirection = Vector3.Zero;
547 m_angularMotorTimescale = 4;
548 m_angularMotorDecayTimescale = 4;
549 m_VhoverHeight = 0;
550// m_VhoverEfficiency = 0.5f;
551 m_VhoverTimescale = 1000;
552 m_VehicleBuoyancy = 0;
553 // m_linearDeflectionEfficiency = 0.5f;
554 // m_linearDeflectionTimescale = 3;
555 // m_angularDeflectionEfficiency = 1;
556 // m_angularDeflectionTimescale = 2;
557 m_verticalAttractionEfficiency = 0.9f;
558 m_verticalAttractionTimescale = 2f;
559 // m_bankingEfficiency = 1;
560 // m_bankingMix = 0.7f;
561 // m_bankingTimescale = 2;
562 // m_referenceFrame = Quaternion.Identity;
563 m_Hoverflags &= ~(VehicleFlag.HOVER_WATER_ONLY | VehicleFlag.HOVER_TERRAIN_ONLY |
564 VehicleFlag.HOVER_GLOBAL_HEIGHT | VehicleFlag.HOVER_UP_ONLY);
565 m_flags &= ~(VehicleFlag.NO_DEFLECTION_UP | VehicleFlag.LIMIT_MOTOR_UP);
566 m_flags |= (VehicleFlag.LIMIT_ROLL_ONLY);
567 break;
568 case Vehicle.TYPE_BALLOON:
569 m_linearFrictionTimescale = new Vector3(5, 5, 5);
570 m_angularFrictionTimescale = new Vector3(10, 10, 10);
571 m_linearMotorDirection = Vector3.Zero;
572 m_linearMotorTimescale = 5;
573 m_linearMotorDecayTimescale = 60;
574 m_angularMotorDirection = Vector3.Zero;
575 m_angularMotorTimescale = 6;
576 m_angularMotorDecayTimescale = 10;
577 m_VhoverHeight = 5;
578// m_VhoverEfficiency = 0.8f;
579 m_VhoverTimescale = 10;
580 m_VehicleBuoyancy = 1;
581 // m_linearDeflectionEfficiency = 0;
582 // m_linearDeflectionTimescale = 5;
583 // m_angularDeflectionEfficiency = 0;
584 // m_angularDeflectionTimescale = 5;
585 m_verticalAttractionEfficiency = 1f;
586 m_verticalAttractionTimescale = 100f;
587 // m_bankingEfficiency = 0;
588 // m_bankingMix = 0.7f;
589 // m_bankingTimescale = 5;
590 // m_referenceFrame = Quaternion.Identity;
591 m_Hoverflags &= ~(VehicleFlag.HOVER_WATER_ONLY | VehicleFlag.HOVER_TERRAIN_ONLY |
592 VehicleFlag.HOVER_UP_ONLY);
593 m_flags &= ~(VehicleFlag.NO_DEFLECTION_UP | VehicleFlag.LIMIT_MOTOR_UP);
594 m_flags |= (VehicleFlag.LIMIT_ROLL_ONLY);
595 m_Hoverflags |= (VehicleFlag.HOVER_GLOBAL_HEIGHT);
596 break;
597
598 }
599 }//end SetDefaultsForType
600
601 internal void Step(float pTimestep, BSScene pParentScene)
602 {
603 if (m_type == Vehicle.TYPE_NONE) return;
604
605 frcount++; // used to limit debug comment output
606 if (frcount > 100)
607 frcount = 0;
608
609 MoveLinear(pTimestep, pParentScene);
610 MoveAngular(pTimestep);
611 LimitRotation(pTimestep);
612 }// end Step
613
614 private void MoveLinear(float pTimestep, BSScene _pParentScene)
615 {
616 if (!m_linearMotorDirection.ApproxEquals(Vector3.Zero, 0.01f)) // requested m_linearMotorDirection is significant
617 {
618 // add drive to body
619 Vector3 addAmount = m_linearMotorDirection/(m_linearMotorTimescale/pTimestep);
620 m_lastLinearVelocityVector += (addAmount*10); // lastLinearVelocityVector is the current body velocity vector?
621
622 // This will work temporarily, but we really need to compare speed on an axis
623 // KF: Limit body velocity to applied velocity?
624 if (Math.Abs(m_lastLinearVelocityVector.X) > Math.Abs(m_linearMotorDirectionLASTSET.X))
625 m_lastLinearVelocityVector.X = m_linearMotorDirectionLASTSET.X;
626 if (Math.Abs(m_lastLinearVelocityVector.Y) > Math.Abs(m_linearMotorDirectionLASTSET.Y))
627 m_lastLinearVelocityVector.Y = m_linearMotorDirectionLASTSET.Y;
628 if (Math.Abs(m_lastLinearVelocityVector.Z) > Math.Abs(m_linearMotorDirectionLASTSET.Z))
629 m_lastLinearVelocityVector.Z = m_linearMotorDirectionLASTSET.Z;
630
631 // decay applied velocity
632 Vector3 decayfraction = ((Vector3.One/(m_linearMotorDecayTimescale/pTimestep)));
633 //Console.WriteLine("decay: " + decayfraction);
634 m_linearMotorDirection -= m_linearMotorDirection * decayfraction * 0.5f;
635 //Console.WriteLine("actual: " + m_linearMotorDirection);
636 }
637 else
638 { // requested is not significant
639 // if what remains of applied is small, zero it.
640 if (m_lastLinearVelocityVector.ApproxEquals(Vector3.Zero, 0.01f))
641 m_lastLinearVelocityVector = Vector3.Zero;
642 }
643
644 // convert requested object velocity to world-referenced vector
645 m_dir = m_lastLinearVelocityVector;
646 Quaternion rot = m_prim.Orientation;
647 Quaternion rotq = new Quaternion(rot.X, rot.Y, rot.Z, rot.W); // rotq = rotation of object
648 m_dir *= rotq; // apply obj rotation to velocity vector
649
650 // add Gravity andBuoyancy
651 // KF: So far I have found no good method to combine a script-requested
652 // .Z velocity and gravity. Therefore only 0g will used script-requested
653 // .Z velocity. >0g (m_VehicleBuoyancy < 1) will used modified gravity only.
654 Vector3 grav = Vector3.Zero;
655 // There is some gravity, make a gravity force vector
656 // that is applied after object velocity.
657 float objMass = m_prim.Mass;
658 // m_VehicleBuoyancy: -1=2g; 0=1g; 1=0g;
659 grav.Z = _pParentScene.DefaultGravity.Z * objMass * (1f - m_VehicleBuoyancy);
660 // Preserve the current Z velocity
661 Vector3 vel_now = m_prim.Velocity;
662 m_dir.Z = vel_now.Z; // Preserve the accumulated falling velocity
663
664 Vector3 pos = m_prim.Position;
665// Vector3 accel = new Vector3(-(m_dir.X - m_lastLinearVelocityVector.X / 0.1f), -(m_dir.Y - m_lastLinearVelocityVector.Y / 0.1f), m_dir.Z - m_lastLinearVelocityVector.Z / 0.1f);
666 Vector3 posChange = new Vector3();
667 posChange.X = pos.X - m_lastPositionVector.X;
668 posChange.Y = pos.Y - m_lastPositionVector.Y;
669 posChange.Z = pos.Z - m_lastPositionVector.Z;
670 double Zchange = Math.Abs(posChange.Z);
671 if (m_BlockingEndPoint != Vector3.Zero)
672 {
673 if (pos.X >= (m_BlockingEndPoint.X - (float)1))
674 {
675 pos.X -= posChange.X + 1;
676 m_prim.Position = pos;
677 }
678 if (pos.Y >= (m_BlockingEndPoint.Y - (float)1))
679 {
680 pos.Y -= posChange.Y + 1;
681 m_prim.Position = pos;
682 }
683 if (pos.Z >= (m_BlockingEndPoint.Z - (float)1))
684 {
685 pos.Z -= posChange.Z + 1;
686 m_prim.Position = pos;
687 }
688 if (pos.X <= 0)
689 {
690 pos.X += posChange.X + 1;
691 m_prim.Position = pos;
692 }
693 if (pos.Y <= 0)
694 {
695 pos.Y += posChange.Y + 1;
696 m_prim.Position = pos;
697 }
698 }
699 if (pos.Z < _pParentScene.GetTerrainHeightAtXY(pos.X, pos.Y))
700 {
701 pos.Z = _pParentScene.GetTerrainHeightAtXY(pos.X, pos.Y) + 2;
702 m_prim.Position = pos;
703 }
704
705 // Check if hovering
706 if ((m_Hoverflags & (VehicleFlag.HOVER_WATER_ONLY | VehicleFlag.HOVER_TERRAIN_ONLY | VehicleFlag.HOVER_GLOBAL_HEIGHT)) != 0)
707 {
708 // We should hover, get the target height
709 if ((m_Hoverflags & VehicleFlag.HOVER_WATER_ONLY) != 0)
710 {
711 m_VhoverTargetHeight = _pParentScene.GetWaterLevel() + m_VhoverHeight;
712 }
713 if ((m_Hoverflags & VehicleFlag.HOVER_TERRAIN_ONLY) != 0)
714 {
715 m_VhoverTargetHeight = _pParentScene.GetTerrainHeightAtXY(pos.X, pos.Y) + m_VhoverHeight;
716 }
717 if ((m_Hoverflags & VehicleFlag.HOVER_GLOBAL_HEIGHT) != 0)
718 {
719 m_VhoverTargetHeight = m_VhoverHeight;
720 }
721
722 if ((m_Hoverflags & VehicleFlag.HOVER_UP_ONLY) != 0)
723 {
724 // If body is aready heigher, use its height as target height
725 if (pos.Z > m_VhoverTargetHeight) m_VhoverTargetHeight = pos.Z;
726 }
727 if ((m_Hoverflags & VehicleFlag.LOCK_HOVER_HEIGHT) != 0)
728 {
729 if ((pos.Z - m_VhoverTargetHeight) > .2 || (pos.Z - m_VhoverTargetHeight) < -.2)
730 {
731 m_prim.Position = pos;
732 }
733 }
734 else
735 {
736 float herr0 = pos.Z - m_VhoverTargetHeight;
737 // Replace Vertical speed with correction figure if significant
738 if (Math.Abs(herr0) > 0.01f)
739 {
740 m_dir.Z = -((herr0 * pTimestep * 50.0f) / m_VhoverTimescale);
741 //KF: m_VhoverEfficiency is not yet implemented
742 }
743 else
744 {
745 m_dir.Z = 0f;
746 }
747 }
748
749// m_VhoverEfficiency = 0f; // 0=boucy, 1=Crit.damped
750// m_VhoverTimescale = 0f; // time to acheive height
751// pTimestep is time since last frame,in secs
752 }
753
754 if ((m_flags & (VehicleFlag.LIMIT_MOTOR_UP)) != 0)
755 {
756 //Start Experimental Values
757 if (Zchange > .3)
758 {
759 grav.Z = (float)(grav.Z * 3);
760 }
761 if (Zchange > .15)
762 {
763 grav.Z = (float)(grav.Z * 2);
764 }
765 if (Zchange > .75)
766 {
767 grav.Z = (float)(grav.Z * 1.5);
768 }
769 if (Zchange > .05)
770 {
771 grav.Z = (float)(grav.Z * 1.25);
772 }
773 if (Zchange > .025)
774 {
775 grav.Z = (float)(grav.Z * 1.125);
776 }
777 float terraintemp = _pParentScene.GetTerrainHeightAtXY(pos.X, pos.Y);
778 float postemp = (pos.Z - terraintemp);
779 if (postemp > 2.5f)
780 {
781 grav.Z = (float)(grav.Z * 1.037125);
782 }
783 //End Experimental Values
784 }
785 if ((m_flags & (VehicleFlag.NO_X)) != 0)
786 {
787 m_dir.X = 0;
788 }
789 if ((m_flags & (VehicleFlag.NO_Y)) != 0)
790 {
791 m_dir.Y = 0;
792 }
793 if ((m_flags & (VehicleFlag.NO_Z)) != 0)
794 {
795 m_dir.Z = 0;
796 }
797
798 m_lastPositionVector = m_prim.Position;
799
800 // Apply velocity
801 m_prim.Velocity = m_dir;
802 // apply gravity force
803 m_prim.Force = grav;
804
805
806 // apply friction
807 Vector3 decayamount = Vector3.One / (m_linearFrictionTimescale / pTimestep);
808 m_lastLinearVelocityVector -= m_lastLinearVelocityVector * decayamount;
809 } // end MoveLinear()
810
811 private void MoveAngular(float pTimestep)
812 {
813 /*
814 private Vector3 m_angularMotorDirection = Vector3.Zero; // angular velocity requested by LSL motor
815 private int m_angularMotorApply = 0; // application frame counter
816 private float m_angularMotorVelocity = 0; // current angular motor velocity (ramps up and down)
817 private float m_angularMotorTimescale = 0; // motor angular velocity ramp up rate
818 private float m_angularMotorDecayTimescale = 0; // motor angular velocity decay rate
819 private Vector3 m_angularFrictionTimescale = Vector3.Zero; // body angular velocity decay rate
820 private Vector3 m_lastAngularVelocity = Vector3.Zero; // what was last applied to body
821 */
822
823 // Get what the body is doing, this includes 'external' influences
824 Vector3 angularVelocity = m_prim.AngularVelocity;
825 // Vector3 angularVelocity = Vector3.Zero;
826
827 if (m_angularMotorApply > 0)
828 {
829 // ramp up to new value
830 // current velocity += error / (time to get there / step interval)
831 // requested speed - last motor speed
832 m_angularMotorVelocity.X += (m_angularMotorDirection.X - m_angularMotorVelocity.X) / (m_angularMotorTimescale / pTimestep);
833 m_angularMotorVelocity.Y += (m_angularMotorDirection.Y - m_angularMotorVelocity.Y) / (m_angularMotorTimescale / pTimestep);
834 m_angularMotorVelocity.Z += (m_angularMotorDirection.Z - m_angularMotorVelocity.Z) / (m_angularMotorTimescale / pTimestep);
835
836 m_angularMotorApply--; // This is done so that if script request rate is less than phys frame rate the expected
837 // velocity may still be acheived.
838 }
839 else
840 {
841 // no motor recently applied, keep the body velocity
842 /* m_angularMotorVelocity.X = angularVelocity.X;
843 m_angularMotorVelocity.Y = angularVelocity.Y;
844 m_angularMotorVelocity.Z = angularVelocity.Z; */
845
846 // and decay the velocity
847 m_angularMotorVelocity -= m_angularMotorVelocity / (m_angularMotorDecayTimescale / pTimestep);
848 } // end motor section
849
850 // Vertical attractor section
851 Vector3 vertattr = Vector3.Zero;
852
853 if (m_verticalAttractionTimescale < 300)
854 {
855 float VAservo = 0.2f / (m_verticalAttractionTimescale * pTimestep);
856 // get present body rotation
857 Quaternion rotq = m_prim.Orientation;
858 // make a vector pointing up
859 Vector3 verterr = Vector3.Zero;
860 verterr.Z = 1.0f;
861 // rotate it to Body Angle
862 verterr = verterr * rotq;
863 // verterr.X and .Y are the World error ammounts. They are 0 when there is no error (Vehicle Body is 'vertical'), and .Z will be 1.
864 // As the body leans to its side |.X| will increase to 1 and .Z fall to 0. As body inverts |.X| will fall and .Z will go
865 // negative. Similar for tilt and |.Y|. .X and .Y must be modulated to prevent a stable inverted body.
866 if (verterr.Z < 0.0f)
867 {
868 verterr.X = 2.0f - verterr.X;
869 verterr.Y = 2.0f - verterr.Y;
870 }
871 // Error is 0 (no error) to +/- 2 (max error)
872 // scale it by VAservo
873 verterr = verterr * VAservo;
874//if (frcount == 0) Console.WriteLine("VAerr=" + verterr);
875
876 // As the body rotates around the X axis, then verterr.Y increases; Rotated around Y then .X increases, so
877 // Change Body angular velocity X based on Y, and Y based on X. Z is not changed.
878 vertattr.X = verterr.Y;
879 vertattr.Y = - verterr.X;
880 vertattr.Z = 0f;
881
882 // scaling appears better usingsquare-law
883 float bounce = 1.0f - (m_verticalAttractionEfficiency * m_verticalAttractionEfficiency);
884 vertattr.X += bounce * angularVelocity.X;
885 vertattr.Y += bounce * angularVelocity.Y;
886
887 } // else vertical attractor is off
888
889 // m_lastVertAttractor = vertattr;
890
891 // Bank section tba
892 // Deflection section tba
893
894 // Sum velocities
895 m_lastAngularVelocity = m_angularMotorVelocity + vertattr; // + bank + deflection
896
897 if ((m_flags & (VehicleFlag.NO_DEFLECTION_UP)) != 0)
898 {
899 m_lastAngularVelocity.X = 0;
900 m_lastAngularVelocity.Y = 0;
901 }
902
903 if (m_lastAngularVelocity.ApproxEquals(Vector3.Zero, 0.01f))
904 {
905 m_lastAngularVelocity = Vector3.Zero; // Reduce small value to zero.
906 }
907
908 // apply friction
909 Vector3 decayamount = Vector3.One / (m_angularFrictionTimescale / pTimestep);
910 m_lastAngularVelocity -= m_lastAngularVelocity * decayamount;
911
912 // Apply to the body
913 m_prim.AngularVelocity = m_lastAngularVelocity;
914
915 } //end MoveAngular
916 internal void LimitRotation(float timestep)
917 {
918 Quaternion rotq = m_prim.Orientation; // rotq = rotation of object
919 Quaternion m_rot = rotq;
920 bool changed = false;
921 if (m_RollreferenceFrame != Quaternion.Identity)
922 {
923 if (rotq.X >= m_RollreferenceFrame.X)
924 {
925 m_rot.X = rotq.X - (m_RollreferenceFrame.X / 2);
926 }
927 if (rotq.Y >= m_RollreferenceFrame.Y)
928 {
929 m_rot.Y = rotq.Y - (m_RollreferenceFrame.Y / 2);
930 }
931 if (rotq.X <= -m_RollreferenceFrame.X)
932 {
933 m_rot.X = rotq.X + (m_RollreferenceFrame.X / 2);
934 }
935 if (rotq.Y <= -m_RollreferenceFrame.Y)
936 {
937 m_rot.Y = rotq.Y + (m_RollreferenceFrame.Y / 2);
938 }
939 changed = true;
940 }
941 if ((m_flags & VehicleFlag.LOCK_ROTATION) != 0)
942 {
943 m_rot.X = 0;
944 m_rot.Y = 0;
945 changed = true;
946 }
947 if (changed)
948 m_prim.Orientation = m_rot;
949 }
950 }
951}
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSPlugin.cs b/OpenSim/Region/Physics/BulletSPlugin/BSPlugin.cs
new file mode 100644
index 0000000..61be56d
--- /dev/null
+++ b/OpenSim/Region/Physics/BulletSPlugin/BSPlugin.cs
@@ -0,0 +1,68 @@
1/*
2 * Copyright (c) Contributors, http://opensimulator.org/
3 * See CONTRIBUTORS.TXT for a full list of copyright holders.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 * * Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * * Redistributions in binary form must reproduce the above copyrightD
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 * * Neither the name of the OpenSimulator Project nor the
13 * names of its contributors may be used to endorse or promote products
14 * derived from this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
17 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19 * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
20 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
27using System;
28using System.Collections.Generic;
29using OpenSim.Framework;
30using OpenSim.Region.Physics.Manager;
31using OpenMetaverse;
32
33namespace OpenSim.Region.Physics.BulletSPlugin
34{
35public class BSPlugin : IPhysicsPlugin
36{
37 //private static readonly log4net.ILog m_log = log4net.LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType);
38
39 private BSScene _mScene;
40
41 public BSPlugin()
42 {
43 }
44
45 public bool Init()
46 {
47 return true;
48 }
49
50 public PhysicsScene GetScene(String sceneIdentifier)
51 {
52 if (_mScene == null)
53 {
54 _mScene = new BSScene(sceneIdentifier);
55 }
56 return (_mScene);
57 }
58
59 public string GetName()
60 {
61 return ("BulletSim");
62 }
63
64 public void Dispose()
65 {
66 }
67}
68}
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSPrim.cs b/OpenSim/Region/Physics/BulletSPlugin/BSPrim.cs
new file mode 100644
index 0000000..bb8d601
--- /dev/null
+++ b/OpenSim/Region/Physics/BulletSPlugin/BSPrim.cs
@@ -0,0 +1,1357 @@
1/*
2 * Copyright (c) Contributors, http://opensimulator.org/
3 * See CONTRIBUTORS.TXT for a full list of copyright holders.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 * * Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * * Redistributions in binary form must reproduce the above copyrightD
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 * * Neither the name of the OpenSimulator Project nor the
13 * names of its contributors may be used to endorse or promote products
14 * derived from this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
17 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19 * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
20 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
27using System;
28using System.Reflection;
29using System.Collections.Generic;
30using System.Xml;
31using log4net;
32using OMV = OpenMetaverse;
33using OpenSim.Framework;
34using OpenSim.Region.Physics.Manager;
35using OpenSim.Region.Physics.ConvexDecompositionDotNet;
36
37namespace OpenSim.Region.Physics.BulletSPlugin
38{
39 [Serializable]
40public sealed class BSPrim : PhysicsActor
41{
42 private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
43 private static readonly string LogHeader = "[BULLETS PRIM]";
44
45 private IMesh _mesh;
46 private PrimitiveBaseShape _pbs;
47 private ShapeData.PhysicsShapeType _shapeType;
48 private ulong _meshKey;
49 private ulong _hullKey;
50 private List<ConvexResult> _hulls;
51
52 private BSScene _scene;
53 private String _avName;
54 private uint _localID = 0;
55
56 // _size is what the user passed. _scale is what we pass to the physics engine with the mesh.
57 // Often _scale is unity because the meshmerizer will apply _size when creating the mesh.
58 private OMV.Vector3 _size; // the multiplier for each mesh dimension as passed by the user
59 private OMV.Vector3 _scale; // the multiplier for each mesh dimension for the mesh as created by the meshmerizer
60
61 private bool _stopped;
62 private bool _grabbed;
63 private bool _isSelected;
64 private bool _isVolumeDetect;
65 private OMV.Vector3 _position;
66 private float _mass;
67 private float _density;
68 private OMV.Vector3 _force;
69 private OMV.Vector3 _velocity;
70 private OMV.Vector3 _torque;
71 private float _collisionScore;
72 private OMV.Vector3 _acceleration;
73 private OMV.Quaternion _orientation;
74 private int _physicsActorType;
75 private bool _isPhysical;
76 private bool _flying;
77 private float _friction;
78 private float _restitution;
79 private bool _setAlwaysRun;
80 private bool _throttleUpdates;
81 private bool _isColliding;
82 private bool _collidingGround;
83 private bool _collidingObj;
84 private bool _floatOnWater;
85 private OMV.Vector3 _rotationalVelocity;
86 private bool _kinematic;
87 private float _buoyancy;
88 private OMV.Vector3 _angularVelocity;
89
90 private List<BSPrim> _childrenPrims;
91 private BSPrim _parentPrim;
92
93 private int _subscribedEventsMs = 0;
94 private int _lastCollisionTime = 0;
95 long _collidingStep;
96 long _collidingGroundStep;
97
98 private BSDynamics _vehicle;
99
100 private OMV.Vector3 _PIDTarget;
101 private bool _usePID;
102 private float _PIDTau;
103 private bool _useHoverPID;
104 private float _PIDHoverHeight;
105 private PIDHoverType _PIDHoverType;
106 private float _PIDHoverTao;
107
108 public BSPrim(uint localID, String primName, BSScene parent_scene, OMV.Vector3 pos, OMV.Vector3 size,
109 OMV.Quaternion rotation, PrimitiveBaseShape pbs, bool pisPhysical)
110 {
111 // m_log.DebugFormat("{0}: BSPrim creation of {1}, id={2}", LogHeader, primName, localID);
112 _localID = localID;
113 _avName = primName;
114 _scene = parent_scene;
115 _position = pos;
116 _size = size;
117 _scale = new OMV.Vector3(1f, 1f, 1f); // the scale will be set by CreateGeom depending on object type
118 _orientation = rotation;
119 _buoyancy = 1f;
120 _velocity = OMV.Vector3.Zero;
121 _rotationalVelocity = OMV.Vector3.Zero;
122 _angularVelocity = OMV.Vector3.Zero;
123 _hullKey = 0;
124 _meshKey = 0;
125 _pbs = pbs;
126 _isPhysical = pisPhysical;
127 _isVolumeDetect = false;
128 _subscribedEventsMs = 0;
129 _friction = _scene.Params.defaultFriction; // TODO: compute based on object material
130 _density = _scene.Params.defaultDensity; // TODO: compute based on object material
131 _restitution = _scene.Params.defaultRestitution;
132 _parentPrim = null; // not a child or a parent
133 _vehicle = new BSDynamics(this); // add vehicleness
134 _childrenPrims = new List<BSPrim>();
135 if (_isPhysical)
136 _mass = CalculateMass();
137 else
138 _mass = 0f;
139 // do the actual object creation at taint time
140 _scene.TaintedObject(delegate()
141 {
142 RecreateGeomAndObject();
143 });
144 }
145
146 // called when this prim is being destroyed and we should free all the resources
147 public void Destroy()
148 {
149 // m_log.DebugFormat("{0}: Destroy", LogHeader);
150 // Undo any vehicle properties
151 _vehicle.ProcessTypeChange(Vehicle.TYPE_NONE);
152 _scene.RemoveVehiclePrim(this); // just to make sure
153 _scene.TaintedObject(delegate()
154 {
155 // everything in the C# world will get garbage collected. Tell the C++ world to free stuff.
156 BulletSimAPI.DestroyObject(_scene.WorldID, _localID);
157 });
158 }
159
160 public override bool Stopped {
161 get { return _stopped; }
162 }
163 public override OMV.Vector3 Size {
164 get { return _size; }
165 set {
166 _size = value;
167 _scene.TaintedObject(delegate()
168 {
169 if (_isPhysical) _mass = CalculateMass(); // changing size changes the mass
170 BulletSimAPI.SetObjectScaleMass(_scene.WorldID, _localID, _scale, _mass, _isPhysical);
171 RecreateGeomAndObject();
172 });
173 }
174 }
175 public override PrimitiveBaseShape Shape {
176 set {
177 _pbs = value;
178 _scene.TaintedObject(delegate()
179 {
180 if (_isPhysical) _mass = CalculateMass(); // changing the shape changes the mass
181 RecreateGeomAndObject();
182 });
183 }
184 }
185 public override uint LocalID {
186 set { _localID = value; }
187 get { return _localID; }
188 }
189 public override bool Grabbed {
190 set { _grabbed = value;
191 }
192 }
193 public override bool Selected {
194 set {
195 _isSelected = value;
196 _scene.TaintedObject(delegate()
197 {
198 SetObjectDynamic();
199 });
200 }
201 }
202 public override void CrossingFailure() { return; }
203
204 // link me to the specified parent
205 public override void link(PhysicsActor obj) {
206 BSPrim parent = (BSPrim)obj;
207 // m_log.DebugFormat("{0}: link {1}/{2} to {3}", LogHeader, _avName, _localID, obj.LocalID);
208 // TODO: decide if this parent checking needs to happen at taint time
209 if (_parentPrim == null)
210 {
211 if (parent != null)
212 {
213 // I don't have a parent so I am joining a linkset
214 parent.AddChildToLinkset(this);
215 }
216 }
217 else
218 {
219 // I already have a parent, is parenting changing?
220 if (parent != _parentPrim)
221 {
222 if (parent == null)
223 {
224 // we are being removed from a linkset
225 _parentPrim.RemoveChildFromLinkset(this);
226 }
227 else
228 {
229 // asking to reparent a prim should not happen
230 m_log.ErrorFormat("{0}: Reparenting a prim. ", LogHeader);
231 }
232 }
233 }
234 return;
235 }
236
237 // delink me from my linkset
238 public override void delink() {
239 // TODO: decide if this parent checking needs to happen at taint time
240 // Race condition here: if link() and delink() in same simulation tick, the delink will not happen
241 // m_log.DebugFormat("{0}: delink {1}/{2}", LogHeader, _avName, _localID);
242 if (_parentPrim != null)
243 {
244 _parentPrim.RemoveChildFromLinkset(this);
245 }
246 return;
247 }
248
249 // I am the root of a linkset and a new child is being added
250 public void AddChildToLinkset(BSPrim pchild)
251 {
252 BSPrim child = pchild;
253 _scene.TaintedObject(delegate()
254 {
255 if (!_childrenPrims.Contains(child))
256 {
257 _childrenPrims.Add(child);
258 child.ParentPrim = this; // the child has gained a parent
259 RecreateGeomAndObject(); // rebuild my shape with the new child added
260 }
261 });
262 return;
263 }
264
265 // I am the root of a linkset and one of my children is being removed.
266 // Safe to call even if the child is not really in my linkset.
267 public void RemoveChildFromLinkset(BSPrim pchild)
268 {
269 BSPrim child = pchild;
270 _scene.TaintedObject(delegate()
271 {
272 if (_childrenPrims.Contains(child))
273 {
274 BulletSimAPI.RemoveConstraint(_scene.WorldID, child.LocalID, this.LocalID);
275 _childrenPrims.Remove(child);
276 child.ParentPrim = null; // the child has lost its parent
277 RecreateGeomAndObject(); // rebuild my shape with the child removed
278 }
279 else
280 {
281 m_log.ErrorFormat("{0}: Asked to remove child from linkset that was not in linkset");
282 }
283 });
284 return;
285 }
286
287 public BSPrim ParentPrim
288 {
289 set { _parentPrim = value; }
290 }
291
292 // return true if we are the root of a linkset (there are children to manage)
293 public bool IsRootOfLinkset
294 {
295 get { return (_parentPrim == null && _childrenPrims.Count != 0); }
296 }
297
298 // Set motion values to zero.
299 // Do it to the properties so the values get set in the physics engine.
300 // Push the setting of the values to the viewer.
301 private void ZeroMotion()
302 {
303 Velocity = OMV.Vector3.Zero;
304 _acceleration = OMV.Vector3.Zero;
305 RotationalVelocity = OMV.Vector3.Zero;
306 base.RequestPhysicsterseUpdate();
307 }
308
309 public override void LockAngularMotion(OMV.Vector3 axis) { return; }
310
311 public override OMV.Vector3 Position {
312 get {
313 // don't do the following GetObjectPosition because this function is called a zillion times
314 // _position = BulletSimAPI.GetObjectPosition(_scene.WorldID, _localID);
315 return _position;
316 }
317 set {
318 _position = value;
319 _scene.TaintedObject(delegate()
320 {
321 BulletSimAPI.SetObjectTranslation(_scene.WorldID, _localID, _position, _orientation);
322 // m_log.DebugFormat("{0}: setPosition: id={1}, position={2}", LogHeader, _localID, _position);
323 });
324 }
325 }
326 public override float Mass {
327 get { return _mass; }
328 }
329 public override OMV.Vector3 Force {
330 get { return _force; }
331 set {
332 _force = value;
333 _scene.TaintedObject(delegate()
334 {
335 BulletSimAPI.SetObjectForce(_scene.WorldID, _localID, _force);
336 });
337 }
338 }
339
340 public override int VehicleType {
341 get {
342 return (int)_vehicle.Type; // if we are a vehicle, return that type
343 }
344 set {
345 Vehicle type = (Vehicle)value;
346 _vehicle.ProcessTypeChange(type);
347 _scene.TaintedObject(delegate()
348 {
349 if (type == Vehicle.TYPE_NONE)
350 {
351 _scene.RemoveVehiclePrim(this);
352 }
353 else
354 {
355 // make it so the scene will call us each tick to do vehicle things
356 _scene.AddVehiclePrim(this);
357 }
358 return;
359 });
360 }
361 }
362 public override void VehicleFloatParam(int param, float value)
363 {
364 _vehicle.ProcessFloatVehicleParam((Vehicle)param, value);
365 }
366 public override void VehicleVectorParam(int param, OMV.Vector3 value)
367 {
368 _vehicle.ProcessVectorVehicleParam((Vehicle)param, value);
369 }
370 public override void VehicleRotationParam(int param, OMV.Quaternion rotation)
371 {
372 _vehicle.ProcessRotationVehicleParam((Vehicle)param, rotation);
373 }
374 public override void VehicleFlags(int param, bool remove)
375 {
376 _vehicle.ProcessVehicleFlags(param, remove);
377 }
378 // Called each simulation step to advance vehicle characteristics
379 public void StepVehicle(float timeStep)
380 {
381 _vehicle.Step(timeStep, _scene);
382 }
383
384 // Allows the detection of collisions with inherently non-physical prims. see llVolumeDetect for more
385 public override void SetVolumeDetect(int param) {
386 bool newValue = (param != 0);
387 if (_isVolumeDetect != newValue)
388 {
389 _isVolumeDetect = newValue;
390 _scene.TaintedObject(delegate()
391 {
392 SetObjectDynamic();
393 });
394 }
395 return;
396 }
397
398 public override OMV.Vector3 GeometricCenter { get { return OMV.Vector3.Zero; } }
399 public override OMV.Vector3 CenterOfMass { get { return OMV.Vector3.Zero; } }
400 public override OMV.Vector3 Velocity {
401 get { return _velocity; }
402 set { _velocity = value;
403 _scene.TaintedObject(delegate()
404 {
405 BulletSimAPI.SetObjectVelocity(_scene.WorldID, LocalID, _velocity);
406 });
407 }
408 }
409 public override OMV.Vector3 Torque {
410 get { return _torque; }
411 set { _torque = value;
412 }
413 }
414 public override float CollisionScore {
415 get { return _collisionScore; }
416 set { _collisionScore = value;
417 }
418 }
419 public override OMV.Vector3 Acceleration {
420 get { return _acceleration; }
421 }
422 public override OMV.Quaternion Orientation {
423 get { return _orientation; }
424 set {
425 _orientation = value;
426 // m_log.DebugFormat("{0}: set orientation: id={1}, ori={2}", LogHeader, LocalID, _orientation);
427 _scene.TaintedObject(delegate()
428 {
429 // _position = BulletSimAPI.GetObjectPosition(_scene.WorldID, _localID);
430 BulletSimAPI.SetObjectTranslation(_scene.WorldID, _localID, _position, _orientation);
431 });
432 }
433 }
434 public override int PhysicsActorType {
435 get { return _physicsActorType; }
436 set { _physicsActorType = value;
437 }
438 }
439 public override bool IsPhysical {
440 get { return _isPhysical; }
441 set {
442 _isPhysical = value;
443 _scene.TaintedObject(delegate()
444 {
445 SetObjectDynamic();
446 });
447 }
448 }
449
450 // An object is static (does not move) if selected or not physical
451 private bool IsStatic
452 {
453 get { return _isSelected || !IsPhysical; }
454 }
455
456 // An object is solid if it's not phantom and if it's not doing VolumeDetect
457 private bool IsSolid
458 {
459 get { return !IsPhantom && !_isVolumeDetect; }
460 }
461
462 // make gravity work if the object is physical and not selected
463 // no locking here because only called when it is safe
464 private void SetObjectDynamic()
465 {
466 // m_log.DebugFormat("{0}: ID={1}, SetObjectDynamic: IsStatic={2}, IsSolid={3}", LogHeader, _localID, IsStatic, IsSolid);
467 // non-physical things work best with a mass of zero
468 if (IsStatic)
469 {
470 _mass = 0f;
471 }
472 else
473 {
474 _mass = CalculateMass();
475 // If it's dynamic, make sure the hull has been created for it
476 // This shouldn't do much work if the object had previously been built
477 RecreateGeomAndObject();
478
479 }
480 BulletSimAPI.SetObjectProperties(_scene.WorldID, LocalID, IsStatic, IsSolid, SubscribedEvents(), _mass);
481 }
482
483 // prims don't fly
484 public override bool Flying {
485 get { return _flying; }
486 set { _flying = value; }
487 }
488 public override bool SetAlwaysRun {
489 get { return _setAlwaysRun; }
490 set { _setAlwaysRun = value; }
491 }
492 public override bool ThrottleUpdates {
493 get { return _throttleUpdates; }
494 set { _throttleUpdates = value; }
495 }
496 public override bool IsColliding {
497 get { return (_collidingStep == _scene.SimulationStep); }
498 set { _isColliding = value; }
499 }
500 public override bool CollidingGround {
501 get { return (_collidingGroundStep == _scene.SimulationStep); }
502 set { _collidingGround = value; }
503 }
504 public override bool CollidingObj {
505 get { return _collidingObj; }
506 set { _collidingObj = value; }
507 }
508 public bool IsPhantom {
509 get {
510 // SceneObjectPart removes phantom objects from the physics scene
511 // so, although we could implement touching and such, we never
512 // are invoked as a phantom object
513 return false;
514 }
515 }
516 public override bool FloatOnWater {
517 set { _floatOnWater = value; }
518 }
519 public override OMV.Vector3 RotationalVelocity {
520 get { return _rotationalVelocity; }
521 set { _rotationalVelocity = value;
522 // m_log.DebugFormat("{0}: RotationalVelocity={1}", LogHeader, _rotationalVelocity);
523 _scene.TaintedObject(delegate()
524 {
525 BulletSimAPI.SetObjectAngularVelocity(_scene.WorldID, LocalID, _rotationalVelocity);
526 });
527 }
528 }
529 public OMV.Vector3 AngularVelocity {
530 get { return _angularVelocity; }
531 set { _angularVelocity = value; }
532 }
533 public override bool Kinematic {
534 get { return _kinematic; }
535 set { _kinematic = value;
536 // m_log.DebugFormat("{0}: Kinematic={1}", LogHeader, _kinematic);
537 }
538 }
539 public override float Buoyancy {
540 get { return _buoyancy; }
541 set { _buoyancy = value;
542 _scene.TaintedObject(delegate()
543 {
544 BulletSimAPI.SetObjectBuoyancy(_scene.WorldID, _localID, _buoyancy);
545 });
546 }
547 }
548
549 // Used for MoveTo
550 public override OMV.Vector3 PIDTarget {
551 set { _PIDTarget = value; }
552 }
553 public override bool PIDActive {
554 set { _usePID = value; }
555 }
556 public override float PIDTau {
557 set { _PIDTau = value; }
558 }
559
560 // Used for llSetHoverHeight and maybe vehicle height
561 // Hover Height will override MoveTo target's Z
562 public override bool PIDHoverActive {
563 set { _useHoverPID = value; }
564 }
565 public override float PIDHoverHeight {
566 set { _PIDHoverHeight = value; }
567 }
568 public override PIDHoverType PIDHoverType {
569 set { _PIDHoverType = value; }
570 }
571 public override float PIDHoverTau {
572 set { _PIDHoverTao = value; }
573 }
574
575 // For RotLookAt
576 public override OMV.Quaternion APIDTarget { set { return; } }
577 public override bool APIDActive { set { return; } }
578 public override float APIDStrength { set { return; } }
579 public override float APIDDamping { set { return; } }
580
581 public override void AddForce(OMV.Vector3 force, bool pushforce) {
582 if (force.IsFinite())
583 {
584 _force.X += force.X;
585 _force.Y += force.Y;
586 _force.Z += force.Z;
587 }
588 else
589 {
590 m_log.WarnFormat("{0}: Got a NaN force applied to a Character", LogHeader);
591 }
592 _scene.TaintedObject(delegate()
593 {
594 BulletSimAPI.SetObjectForce(_scene.WorldID, _localID, _force);
595 });
596 }
597
598 public override void AddAngularForce(OMV.Vector3 force, bool pushforce) {
599 // m_log.DebugFormat("{0}: AddAngularForce. f={1}, push={2}", LogHeader, force, pushforce);
600 }
601 public override void SetMomentum(OMV.Vector3 momentum) {
602 }
603 public override void SubscribeEvents(int ms) {
604 _subscribedEventsMs = ms;
605 _lastCollisionTime = Util.EnvironmentTickCount() - _subscribedEventsMs; // make first collision happen
606 }
607 public override void UnSubscribeEvents() {
608 _subscribedEventsMs = 0;
609 }
610 public override bool SubscribedEvents() {
611 return (_subscribedEventsMs > 0);
612 }
613
614 #region Mass Calculation
615
616 private float CalculateMass()
617 {
618 float volume = _size.X * _size.Y * _size.Z; // default
619 float tmp;
620
621 float returnMass = 0;
622 float hollowAmount = (float)_pbs.ProfileHollow * 2.0e-5f;
623 float hollowVolume = hollowAmount * hollowAmount;
624
625 switch (_pbs.ProfileShape)
626 {
627 case ProfileShape.Square:
628 // default box
629
630 if (_pbs.PathCurve == (byte)Extrusion.Straight)
631 {
632 if (hollowAmount > 0.0)
633 {
634 switch (_pbs.HollowShape)
635 {
636 case HollowShape.Square:
637 case HollowShape.Same:
638 break;
639
640 case HollowShape.Circle:
641
642 hollowVolume *= 0.78539816339f;
643 break;
644
645 case HollowShape.Triangle:
646
647 hollowVolume *= (0.5f * .5f);
648 break;
649
650 default:
651 hollowVolume = 0;
652 break;
653 }
654 volume *= (1.0f - hollowVolume);
655 }
656 }
657
658 else if (_pbs.PathCurve == (byte)Extrusion.Curve1)
659 {
660 //a tube
661
662 volume *= 0.78539816339e-2f * (float)(200 - _pbs.PathScaleX);
663 tmp= 1.0f -2.0e-2f * (float)(200 - _pbs.PathScaleY);
664 volume -= volume*tmp*tmp;
665
666 if (hollowAmount > 0.0)
667 {
668 hollowVolume *= hollowAmount;
669
670 switch (_pbs.HollowShape)
671 {
672 case HollowShape.Square:
673 case HollowShape.Same:
674 break;
675
676 case HollowShape.Circle:
677 hollowVolume *= 0.78539816339f;;
678 break;
679
680 case HollowShape.Triangle:
681 hollowVolume *= 0.5f * 0.5f;
682 break;
683 default:
684 hollowVolume = 0;
685 break;
686 }
687 volume *= (1.0f - hollowVolume);
688 }
689 }
690
691 break;
692
693 case ProfileShape.Circle:
694
695 if (_pbs.PathCurve == (byte)Extrusion.Straight)
696 {
697 volume *= 0.78539816339f; // elipse base
698
699 if (hollowAmount > 0.0)
700 {
701 switch (_pbs.HollowShape)
702 {
703 case HollowShape.Same:
704 case HollowShape.Circle:
705 break;
706
707 case HollowShape.Square:
708 hollowVolume *= 0.5f * 2.5984480504799f;
709 break;
710
711 case HollowShape.Triangle:
712 hollowVolume *= .5f * 1.27323954473516f;
713 break;
714
715 default:
716 hollowVolume = 0;
717 break;
718 }
719 volume *= (1.0f - hollowVolume);
720 }
721 }
722
723 else if (_pbs.PathCurve == (byte)Extrusion.Curve1)
724 {
725 volume *= 0.61685027506808491367715568749226e-2f * (float)(200 - _pbs.PathScaleX);
726 tmp = 1.0f - .02f * (float)(200 - _pbs.PathScaleY);
727 volume *= (1.0f - tmp * tmp);
728
729 if (hollowAmount > 0.0)
730 {
731
732 // calculate the hollow volume by it's shape compared to the prim shape
733 hollowVolume *= hollowAmount;
734
735 switch (_pbs.HollowShape)
736 {
737 case HollowShape.Same:
738 case HollowShape.Circle:
739 break;
740
741 case HollowShape.Square:
742 hollowVolume *= 0.5f * 2.5984480504799f;
743 break;
744
745 case HollowShape.Triangle:
746 hollowVolume *= .5f * 1.27323954473516f;
747 break;
748
749 default:
750 hollowVolume = 0;
751 break;
752 }
753 volume *= (1.0f - hollowVolume);
754 }
755 }
756 break;
757
758 case ProfileShape.HalfCircle:
759 if (_pbs.PathCurve == (byte)Extrusion.Curve1)
760 {
761 volume *= 0.52359877559829887307710723054658f;
762 }
763 break;
764
765 case ProfileShape.EquilateralTriangle:
766
767 if (_pbs.PathCurve == (byte)Extrusion.Straight)
768 {
769 volume *= 0.32475953f;
770
771 if (hollowAmount > 0.0)
772 {
773
774 // calculate the hollow volume by it's shape compared to the prim shape
775 switch (_pbs.HollowShape)
776 {
777 case HollowShape.Same:
778 case HollowShape.Triangle:
779 hollowVolume *= .25f;
780 break;
781
782 case HollowShape.Square:
783 hollowVolume *= 0.499849f * 3.07920140172638f;
784 break;
785
786 case HollowShape.Circle:
787 // Hollow shape is a perfect cyllinder in respect to the cube's scale
788 // Cyllinder hollow volume calculation
789
790 hollowVolume *= 0.1963495f * 3.07920140172638f;
791 break;
792
793 default:
794 hollowVolume = 0;
795 break;
796 }
797 volume *= (1.0f - hollowVolume);
798 }
799 }
800 else if (_pbs.PathCurve == (byte)Extrusion.Curve1)
801 {
802 volume *= 0.32475953f;
803 volume *= 0.01f * (float)(200 - _pbs.PathScaleX);
804 tmp = 1.0f - .02f * (float)(200 - _pbs.PathScaleY);
805 volume *= (1.0f - tmp * tmp);
806
807 if (hollowAmount > 0.0)
808 {
809
810 hollowVolume *= hollowAmount;
811
812 switch (_pbs.HollowShape)
813 {
814 case HollowShape.Same:
815 case HollowShape.Triangle:
816 hollowVolume *= .25f;
817 break;
818
819 case HollowShape.Square:
820 hollowVolume *= 0.499849f * 3.07920140172638f;
821 break;
822
823 case HollowShape.Circle:
824
825 hollowVolume *= 0.1963495f * 3.07920140172638f;
826 break;
827
828 default:
829 hollowVolume = 0;
830 break;
831 }
832 volume *= (1.0f - hollowVolume);
833 }
834 }
835 break;
836
837 default:
838 break;
839 }
840
841
842
843 float taperX1;
844 float taperY1;
845 float taperX;
846 float taperY;
847 float pathBegin;
848 float pathEnd;
849 float profileBegin;
850 float profileEnd;
851
852 if (_pbs.PathCurve == (byte)Extrusion.Straight || _pbs.PathCurve == (byte)Extrusion.Flexible)
853 {
854 taperX1 = _pbs.PathScaleX * 0.01f;
855 if (taperX1 > 1.0f)
856 taperX1 = 2.0f - taperX1;
857 taperX = 1.0f - taperX1;
858
859 taperY1 = _pbs.PathScaleY * 0.01f;
860 if (taperY1 > 1.0f)
861 taperY1 = 2.0f - taperY1;
862 taperY = 1.0f - taperY1;
863 }
864 else
865 {
866 taperX = _pbs.PathTaperX * 0.01f;
867 if (taperX < 0.0f)
868 taperX = -taperX;
869 taperX1 = 1.0f - taperX;
870
871 taperY = _pbs.PathTaperY * 0.01f;
872 if (taperY < 0.0f)
873 taperY = -taperY;
874 taperY1 = 1.0f - taperY;
875
876 }
877
878
879 volume *= (taperX1 * taperY1 + 0.5f * (taperX1 * taperY + taperX * taperY1) + 0.3333333333f * taperX * taperY);
880
881 pathBegin = (float)_pbs.PathBegin * 2.0e-5f;
882 pathEnd = 1.0f - (float)_pbs.PathEnd * 2.0e-5f;
883 volume *= (pathEnd - pathBegin);
884
885 // this is crude aproximation
886 profileBegin = (float)_pbs.ProfileBegin * 2.0e-5f;
887 profileEnd = 1.0f - (float)_pbs.ProfileEnd * 2.0e-5f;
888 volume *= (profileEnd - profileBegin);
889
890 returnMass = _density * volume;
891
892 if (IsRootOfLinkset)
893 {
894 foreach (BSPrim prim in _childrenPrims)
895 {
896 returnMass += prim.CalculateMass();
897 }
898 }
899
900 if (returnMass <= 0)
901 returnMass = 0.0001f;
902
903 if (returnMass > _scene.MaximumObjectMass)
904 returnMass = _scene.MaximumObjectMass;
905
906 return returnMass;
907 }// end CalculateMass
908 #endregion Mass Calculation
909
910 // Create the geometry information in Bullet for later use
911 // The objects needs a hull if it's physical otherwise a mesh is enough
912 // No locking here because this is done when we know physics is not simulating
913 // if 'forceRebuild' is true, the geometry is rebuilt. Otherwise a previously built version is used
914 private void CreateGeom(bool forceRebuild)
915 {
916 // the mesher thought this was too simple to mesh. Use a native Bullet collision shape.
917 if (!_scene.NeedsMeshing(_pbs))
918 {
919 if (_pbs.ProfileShape == ProfileShape.HalfCircle && _pbs.PathCurve == (byte)Extrusion.Curve1)
920 {
921 if (_size.X == _size.Y && _size.Y == _size.Z && _size.X == _size.Z)
922 {
923 // m_log.DebugFormat("{0}: CreateGeom: Defaulting to sphere of size {1}", LogHeader, _size);
924 _shapeType = ShapeData.PhysicsShapeType.SHAPE_SPHERE;
925 // Bullet native objects are scaled by the Bullet engine so pass the size in
926 _scale = _size;
927 }
928 }
929 else
930 {
931 // m_log.DebugFormat("{0}: CreateGeom: Defaulting to box. lid={1}, size={2}", LogHeader, LocalID, _size);
932 _shapeType = ShapeData.PhysicsShapeType.SHAPE_BOX;
933 _scale = _size;
934 }
935 }
936 else
937 {
938 if (IsPhysical)
939 {
940 if (forceRebuild || _hullKey == 0)
941 {
942 // physical objects require a hull for interaction.
943 // This will create the mesh if it doesn't already exist
944 CreateGeomHull();
945 }
946 }
947 else
948 {
949 if (forceRebuild || _meshKey == 0)
950 {
951 // Static (non-physical) objects only need a mesh for bumping into
952 CreateGeomMesh();
953 }
954 }
955 }
956 }
957
958 // No locking here because this is done when we know physics is not simulating
959 private void CreateGeomMesh()
960 {
961 float lod = _pbs.SculptEntry ? _scene.SculptLOD : _scene.MeshLOD;
962 ulong newMeshKey = (ulong)_pbs.GetMeshKey(_size, lod);
963 // m_log.DebugFormat("{0}: CreateGeomMesh: lID={1}, oldKey={2}, newKey={3}", LogHeader, _localID, _meshKey, newMeshKey);
964
965 // if this new shape is the same as last time, don't recreate the mesh
966 if (_meshKey == newMeshKey) return;
967
968 // Since we're recreating new, get rid of any previously generated shape
969 if (_meshKey != 0)
970 {
971 // m_log.DebugFormat("{0}: CreateGeom: deleting old mesh. lID={1}, Key={2}", LogHeader, _localID, _meshKey);
972 BulletSimAPI.DestroyMesh(_scene.WorldID, _meshKey);
973 _mesh = null;
974 _meshKey = 0;
975 }
976
977 _meshKey = newMeshKey;
978 // always pass false for physicalness as this creates some sort of bounding box which we don't need
979 _mesh = _scene.mesher.CreateMesh(_avName, _pbs, _size, lod, false);
980
981 int[] indices = _mesh.getIndexListAsInt();
982 List<OMV.Vector3> vertices = _mesh.getVertexList();
983
984 float[] verticesAsFloats = new float[vertices.Count * 3];
985 int vi = 0;
986 foreach (OMV.Vector3 vv in vertices)
987 {
988 // m_log.DebugFormat("{0}: {1}: <{2:0.00}, {3:0.00}, {4:0.00}>", LogHeader, vi / 3, vv.X, vv.Y, vv.Z);
989 verticesAsFloats[vi++] = vv.X;
990 verticesAsFloats[vi++] = vv.Y;
991 verticesAsFloats[vi++] = vv.Z;
992 }
993
994 // m_log.DebugFormat("{0}: CreateGeomMesh: calling CreateMesh. lid={1}, key={2}, indices={3}, vertices={4}",
995 // LogHeader, _localID, _meshKey, indices.Length, vertices.Count);
996 BulletSimAPI.CreateMesh(_scene.WorldID, _meshKey, indices.GetLength(0), indices,
997 vertices.Count, verticesAsFloats);
998
999 _shapeType = ShapeData.PhysicsShapeType.SHAPE_MESH;
1000 // meshes are already scaled by the meshmerizer
1001 _scale = new OMV.Vector3(1f, 1f, 1f);
1002 return;
1003 }
1004
1005 // No locking here because this is done when we know physics is not simulating
1006 private void CreateGeomHull()
1007 {
1008 float lod = _pbs.SculptEntry ? _scene.SculptLOD : _scene.MeshLOD;
1009 ulong newHullKey = (ulong)_pbs.GetMeshKey(_size, lod);
1010 // m_log.DebugFormat("{0}: CreateGeomHull: lID={1}, oldKey={2}, newKey={3}", LogHeader, _localID, _hullKey, newHullKey);
1011
1012 // if the hull hasn't changed, don't rebuild it
1013 if (newHullKey == _hullKey) return;
1014
1015 // Since we're recreating new, get rid of any previously generated shape
1016 if (_hullKey != 0)
1017 {
1018 // m_log.DebugFormat("{0}: CreateGeom: deleting old hull. Key={1}", LogHeader, _hullKey);
1019 BulletSimAPI.DestroyHull(_scene.WorldID, _hullKey);
1020 _hullKey = 0;
1021 _hulls.Clear();
1022 BulletSimAPI.DestroyMesh(_scene.WorldID, _meshKey);
1023 _mesh = null; // the mesh cannot match either
1024 _meshKey = 0;
1025 }
1026
1027 _hullKey = newHullKey;
1028 if (_meshKey != _hullKey)
1029 {
1030 // if the underlying mesh has changed, rebuild it
1031 CreateGeomMesh();
1032 }
1033
1034 int[] indices = _mesh.getIndexListAsInt();
1035 List<OMV.Vector3> vertices = _mesh.getVertexList();
1036
1037 //format conversion from IMesh format to DecompDesc format
1038 List<int> convIndices = new List<int>();
1039 List<float3> convVertices = new List<float3>();
1040 for (int ii = 0; ii < indices.GetLength(0); ii++)
1041 {
1042 convIndices.Add(indices[ii]);
1043 }
1044 foreach (OMV.Vector3 vv in vertices)
1045 {
1046 convVertices.Add(new float3(vv.X, vv.Y, vv.Z));
1047 }
1048
1049 // setup and do convex hull conversion
1050 _hulls = new List<ConvexResult>();
1051 DecompDesc dcomp = new DecompDesc();
1052 dcomp.mIndices = convIndices;
1053 dcomp.mVertices = convVertices;
1054 ConvexBuilder convexBuilder = new ConvexBuilder(HullReturn);
1055 // create the hull into the _hulls variable
1056 convexBuilder.process(dcomp);
1057
1058 // Convert the vertices and indices for passing to unmanaged
1059 // The hull information is passed as a large floating point array.
1060 // The format is:
1061 // convHulls[0] = number of hulls
1062 // convHulls[1] = number of vertices in first hull
1063 // convHulls[2] = hull centroid X coordinate
1064 // convHulls[3] = hull centroid Y coordinate
1065 // convHulls[4] = hull centroid Z coordinate
1066 // convHulls[5] = first hull vertex X
1067 // convHulls[6] = first hull vertex Y
1068 // convHulls[7] = first hull vertex Z
1069 // convHulls[8] = second hull vertex X
1070 // ...
1071 // convHulls[n] = number of vertices in second hull
1072 // convHulls[n+1] = second hull centroid X coordinate
1073 // ...
1074 //
1075 // TODO: is is very inefficient. Someday change the convex hull generator to return
1076 // data structures that do not need to be converted in order to pass to Bullet.
1077 // And maybe put the values directly into pinned memory rather than marshaling.
1078 int hullCount = _hulls.Count;
1079 int totalVertices = 1; // include one for the count of the hulls
1080 foreach (ConvexResult cr in _hulls)
1081 {
1082 totalVertices += 4; // add four for the vertex count and centroid
1083 totalVertices += cr.HullIndices.Count * 3; // we pass just triangles
1084 }
1085 float[] convHulls = new float[totalVertices];
1086
1087 convHulls[0] = (float)hullCount;
1088 int jj = 1;
1089 foreach (ConvexResult cr in _hulls)
1090 {
1091 // copy vertices for index access
1092 float3[] verts = new float3[cr.HullVertices.Count];
1093 int kk = 0;
1094 foreach (float3 ff in cr.HullVertices)
1095 {
1096 verts[kk++] = ff;
1097 }
1098
1099 // add to the array one hull's worth of data
1100 convHulls[jj++] = cr.HullIndices.Count;
1101 convHulls[jj++] = 0f; // centroid x,y,z
1102 convHulls[jj++] = 0f;
1103 convHulls[jj++] = 0f;
1104 foreach (int ind in cr.HullIndices)
1105 {
1106 convHulls[jj++] = verts[ind].x;
1107 convHulls[jj++] = verts[ind].y;
1108 convHulls[jj++] = verts[ind].z;
1109 }
1110 }
1111
1112 // create the hull definition in Bullet
1113 // m_log.DebugFormat("{0}: CreateGeom: calling CreateHull. lid={1}, key={2}, hulls={3}", LogHeader, _localID, _hullKey, hullCount);
1114 BulletSimAPI.CreateHull(_scene.WorldID, _hullKey, hullCount, convHulls);
1115 _shapeType = ShapeData.PhysicsShapeType.SHAPE_HULL;
1116 // meshes are already scaled by the meshmerizer
1117 _scale = new OMV.Vector3(1f, 1f, 1f);
1118 return;
1119 }
1120
1121 // Callback from convex hull creater with a newly created hull.
1122 // Just add it to the collection of hulls for this shape.
1123 private void HullReturn(ConvexResult result)
1124 {
1125 _hulls.Add(result);
1126 return;
1127 }
1128
1129 // Create an object in Bullet
1130 // No locking here because this is done when the physics engine is not simulating
1131 private void CreateObject()
1132 {
1133 if (IsRootOfLinkset)
1134 {
1135 // Create a linkset around this object
1136 // CreateLinksetWithCompoundHull();
1137 CreateLinksetWithConstraints();
1138 }
1139 else
1140 {
1141 // simple object
1142 // the mesh or hull must have already been created in Bullet
1143 ShapeData shape;
1144 FillShapeInfo(out shape);
1145 // m_log.DebugFormat("{0}: CreateObject: lID={1}, shape={2}", LogHeader, _localID, shape.Type);
1146 BulletSimAPI.CreateObject(_scene.WorldID, shape);
1147 }
1148 }
1149
1150 // Create a linkset by creating a compound hull at the root prim that consists of all
1151 // the children.
1152 // NOTE: This does not allow proper collisions with the children prims so it is not a workable solution
1153 void CreateLinksetWithCompoundHull()
1154 {
1155 // If I am the root prim of a linkset, replace my physical shape with all the
1156 // pieces of the children.
1157 // All of the children should have called CreateGeom so they have a hull
1158 // in the physics engine already. Here we pull together all of those hulls
1159 // into one shape.
1160 int totalPrimsInLinkset = _childrenPrims.Count + 1;
1161 // m_log.DebugFormat("{0}: CreateLinkset. Root prim={1}, prims={2}", LogHeader, LocalID, totalPrimsInLinkset);
1162 ShapeData[] shapes = new ShapeData[totalPrimsInLinkset];
1163 FillShapeInfo(out shapes[0]);
1164 int ii = 1;
1165 foreach (BSPrim prim in _childrenPrims)
1166 {
1167 // m_log.DebugFormat("{0}: CreateLinkset: adding prim {1}", LogHeader, prim.LocalID);
1168 prim.FillShapeInfo(out shapes[ii]);
1169 ii++;
1170 }
1171 BulletSimAPI.CreateLinkset(_scene.WorldID, totalPrimsInLinkset, shapes);
1172 }
1173
1174 // Copy prim's info into the BulletSim shape description structure
1175 public void FillShapeInfo(out ShapeData shape)
1176 {
1177 shape.ID = _localID;
1178 shape.Type = _shapeType;
1179 shape.Position = _position;
1180 shape.Rotation = _orientation;
1181 shape.Velocity = _velocity;
1182 shape.Scale = _scale;
1183 shape.Mass = _isPhysical ? _mass : 0f;
1184 shape.Buoyancy = _buoyancy;
1185 shape.HullKey = _hullKey;
1186 shape.MeshKey = _meshKey;
1187 shape.Friction = _friction;
1188 shape.Restitution = _restitution;
1189 shape.Collidable = (!IsPhantom) ? ShapeData.numericTrue : ShapeData.numericFalse;
1190 shape.Static = _isPhysical ? ShapeData.numericFalse : ShapeData.numericTrue;
1191 }
1192
1193 // Create the linkset by putting constraints between the objects of the set so they cannot move
1194 // relative to each other.
1195 // TODO: make this more effeicient: a large linkset gets rebuilt over and over and prims are added
1196 void CreateLinksetWithConstraints()
1197 {
1198 // m_log.DebugFormat("{0}: CreateLinkset. Root prim={1}, prims={2}", LogHeader, LocalID, _childrenPrims.Count+1);
1199
1200 // remove any constraints that might be in place
1201 foreach (BSPrim prim in _childrenPrims)
1202 {
1203 // m_log.DebugFormat("{0}: CreateLinkset: RemoveConstraint between root prim {1} and child prim {2}", LogHeader, LocalID, prim.LocalID);
1204 BulletSimAPI.RemoveConstraint(_scene.WorldID, LocalID, prim.LocalID);
1205 }
1206 // create constraints between the root prim and each of the children
1207 foreach (BSPrim prim in _childrenPrims)
1208 {
1209 // m_log.DebugFormat("{0}: CreateLinkset: AddConstraint between root prim {1} and child prim {2}", LogHeader, LocalID, prim.LocalID);
1210
1211 // Zero motion for children so they don't interpolate
1212 prim.ZeroMotion();
1213
1214 // relative position normalized to the root prim
1215 OMV.Vector3 childRelativePosition = (prim._position - this._position) * OMV.Quaternion.Inverse(this._orientation);
1216
1217 // relative rotation of the child to the parent
1218 OMV.Quaternion relativeRotation = OMV.Quaternion.Inverse(prim._orientation) * this._orientation;
1219
1220 // this is a constraint that allows no freedom of movement between the two objects
1221 // http://bulletphysics.org/Bullet/phpBB3/viewtopic.php?t=4818
1222 BulletSimAPI.AddConstraint(_scene.WorldID, LocalID, prim.LocalID,
1223 childRelativePosition,
1224 relativeRotation,
1225 OMV.Vector3.Zero,
1226 OMV.Quaternion.Identity,
1227 OMV.Vector3.Zero, OMV.Vector3.Zero,
1228 OMV.Vector3.Zero, OMV.Vector3.Zero);
1229 }
1230 }
1231
1232 // Rebuild the geometry and object.
1233 // This is called when the shape changes so we need to recreate the mesh/hull.
1234 // No locking here because this is done when the physics engine is not simulating
1235 private void RecreateGeomAndObject()
1236 {
1237 // m_log.DebugFormat("{0}: RecreateGeomAndObject. lID={1}", LogHeader, _localID);
1238 CreateGeom(true);
1239 CreateObject();
1240 return;
1241 }
1242
1243 // The physics engine says that properties have updated. Update same and inform
1244 // the world that things have changed.
1245 // TODO: do we really need to check for changed? Maybe just copy values and call RequestPhysicsterseUpdate()
1246 enum UpdatedProperties {
1247 Position = 1 << 0,
1248 Rotation = 1 << 1,
1249 Velocity = 1 << 2,
1250 Acceleration = 1 << 3,
1251 RotationalVel = 1 << 4
1252 }
1253
1254 const float ROTATION_TOLERANCE = 0.01f;
1255 const float VELOCITY_TOLERANCE = 0.001f;
1256 const float POSITION_TOLERANCE = 0.05f;
1257 const float ACCELERATION_TOLERANCE = 0.01f;
1258 const float ROTATIONAL_VELOCITY_TOLERANCE = 0.01f;
1259 const bool SHOULD_DAMP_UPDATES = false;
1260
1261 public void UpdateProperties(EntityProperties entprop)
1262 {
1263 UpdatedProperties changed = 0;
1264 if (SHOULD_DAMP_UPDATES)
1265 {
1266 // assign to the local variables so the normal set action does not happen
1267 // if (_position != entprop.Position)
1268 if (!_position.ApproxEquals(entprop.Position, POSITION_TOLERANCE))
1269 {
1270 _position = entprop.Position;
1271 // m_log.DebugFormat("{0}: UpdateProperties: id={1}, pos = {2}", LogHeader, LocalID, _position);
1272 changed |= UpdatedProperties.Position;
1273 }
1274 // if (_orientation != entprop.Rotation)
1275 if (!_orientation.ApproxEquals(entprop.Rotation, ROTATION_TOLERANCE))
1276 {
1277 _orientation = entprop.Rotation;
1278 // m_log.DebugFormat("{0}: UpdateProperties: id={1}, rot = {2}", LogHeader, LocalID, _orientation);
1279 changed |= UpdatedProperties.Rotation;
1280 }
1281 // if (_velocity != entprop.Velocity)
1282 if (!_velocity.ApproxEquals(entprop.Velocity, VELOCITY_TOLERANCE))
1283 {
1284 _velocity = entprop.Velocity;
1285 // m_log.DebugFormat("{0}: UpdateProperties: velocity = {1}", LogHeader, _velocity);
1286 changed |= UpdatedProperties.Velocity;
1287 }
1288 // if (_acceleration != entprop.Acceleration)
1289 if (!_acceleration.ApproxEquals(entprop.Acceleration, ACCELERATION_TOLERANCE))
1290 {
1291 _acceleration = entprop.Acceleration;
1292 // m_log.DebugFormat("{0}: UpdateProperties: acceleration = {1}", LogHeader, _acceleration);
1293 changed |= UpdatedProperties.Acceleration;
1294 }
1295 // if (_rotationalVelocity != entprop.RotationalVelocity)
1296 if (!_rotationalVelocity.ApproxEquals(entprop.RotationalVelocity, ROTATIONAL_VELOCITY_TOLERANCE))
1297 {
1298 _rotationalVelocity = entprop.RotationalVelocity;
1299 // m_log.DebugFormat("{0}: UpdateProperties: rotationalVelocity = {1}", LogHeader, _rotationalVelocity);
1300 changed |= UpdatedProperties.RotationalVel;
1301 }
1302 if (changed != 0)
1303 {
1304 // m_log.DebugFormat("{0}: UpdateProperties: id={1}, c={2}, pos={3}, rot={4}", LogHeader, LocalID, changed, _position, _orientation);
1305 // Only update the position of single objects and linkset roots
1306 if (this._parentPrim == null)
1307 {
1308 // m_log.DebugFormat("{0}: RequestTerseUpdate. id={1}, ch={2}, pos={3}, rot={4}", LogHeader, LocalID, changed, _position, _orientation);
1309 base.RequestPhysicsterseUpdate();
1310 }
1311 }
1312 }
1313 else
1314 {
1315 // Don't check for damping here -- it's done in BulletSim and SceneObjectPart.
1316
1317 // Only updates only for individual prims and for the root object of a linkset.
1318 if (this._parentPrim == null)
1319 {
1320 // Assign to the local variables so the normal set action does not happen
1321 _position = entprop.Position;
1322 _orientation = entprop.Rotation;
1323 _velocity = entprop.Velocity;
1324 _acceleration = entprop.Acceleration;
1325 _rotationalVelocity = entprop.RotationalVelocity;
1326 // m_log.DebugFormat("{0}: RequestTerseUpdate. id={1}, ch={2}, pos={3}, rot={4}", LogHeader, LocalID, changed, _position, _orientation);
1327 base.RequestPhysicsterseUpdate();
1328 }
1329 }
1330 }
1331
1332 // I've collided with something
1333 public void Collide(uint collidingWith, ActorTypes type, OMV.Vector3 contactPoint, OMV.Vector3 contactNormal, float pentrationDepth)
1334 {
1335 // m_log.DebugFormat("{0}: Collide: ms={1}, id={2}, with={3}", LogHeader, _subscribedEventsMs, LocalID, collidingWith);
1336
1337 // The following lines make IsColliding() and IsCollidingGround() work
1338 _collidingStep = _scene.SimulationStep;
1339 if (collidingWith == BSScene.TERRAIN_ID || collidingWith == BSScene.GROUNDPLANE_ID)
1340 {
1341 _collidingGroundStep = _scene.SimulationStep;
1342 }
1343
1344 if (_subscribedEventsMs == 0) return; // nothing in the object is waiting for collision events
1345 // throttle the collisions to the number of milliseconds specified in the subscription
1346 int nowTime = _scene.SimulationNowTime;
1347 if (nowTime < (_lastCollisionTime + _subscribedEventsMs)) return;
1348 _lastCollisionTime = nowTime;
1349
1350 // create the event for the collision
1351 Dictionary<uint, ContactPoint> contactPoints = new Dictionary<uint, ContactPoint>();
1352 contactPoints.Add(collidingWith, new ContactPoint(contactPoint, contactNormal, pentrationDepth));
1353 CollisionEventUpdate args = new CollisionEventUpdate(LocalID, (int)type, 1, contactPoints);
1354 base.SendCollisionUpdate(args);
1355 }
1356}
1357}
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSScene.cs b/OpenSim/Region/Physics/BulletSPlugin/BSScene.cs
new file mode 100644
index 0000000..7704002
--- /dev/null
+++ b/OpenSim/Region/Physics/BulletSPlugin/BSScene.cs
@@ -0,0 +1,860 @@
1/*
2 * Copyright (c) Contributors, http://opensimulator.org/
3 * See CONTRIBUTORS.TXT for a full list of copyright holders.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 * * Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * * Redistributions in binary form must reproduce the above copyrightD
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 * * Neither the name of the OpenSimulator Project nor the
13 * names of its contributors may be used to endorse or promote products
14 * derived from this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
17 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19 * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
20 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
27using System;
28using System.Collections.Generic;
29using System.Runtime.InteropServices;
30using System.Text;
31using System.Threading;
32using Nini.Config;
33using log4net;
34using OpenSim.Framework;
35using OpenSim.Region.Physics.Manager;
36using OpenMetaverse;
37using OpenSim.Region.Framework;
38
39// TODOs for BulletSim (for BSScene, BSPrim, BSCharacter and BulletSim)
40// Adjust character capsule size when height is adjusted (ScenePresence.SetHeight)
41// Test sculpties
42// Compute physics FPS reasonably
43// Based on material, set density and friction
44// More efficient memory usage in passing hull information from BSPrim to BulletSim
45// Four states of prim: Physical, regular, phantom and selected. Are we modeling these correctly?
46// In SL one can set both physical and phantom (gravity, does not effect others, makes collisions with ground)
47// At the moment, physical and phantom causes object to drop through the terrain
48// Should prim.link() and prim.delink() membership checking happen at taint time?
49// Mesh sharing. Use meshHash to tell if we already have a hull of that shape and only create once
50// Do attachments need to be handled separately? Need collision events. Do not collide with VolumeDetect
51// Implement the genCollisions feature in BulletSim::SetObjectProperties (don't pass up unneeded collisions)
52// Implement LockAngularMotion
53// Decide if clearing forces is the right thing to do when setting position (BulletSim::SetObjectTranslation)
54// Does NeedsMeshing() really need to exclude all the different shapes?
55//
56namespace OpenSim.Region.Physics.BulletSPlugin
57{
58public class BSScene : PhysicsScene, IPhysicsParameters
59{
60 private static readonly ILog m_log = LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType);
61 private static readonly string LogHeader = "[BULLETS SCENE]";
62
63 public string BulletSimVersion = "?";
64
65 private Dictionary<uint, BSCharacter> m_avatars = new Dictionary<uint, BSCharacter>();
66 private Dictionary<uint, BSPrim> m_prims = new Dictionary<uint, BSPrim>();
67 private List<BSPrim> m_vehicles = new List<BSPrim>();
68 private float[] m_heightMap;
69 private float m_waterLevel;
70 private uint m_worldID;
71 public uint WorldID { get { return m_worldID; } }
72
73 private bool m_initialized = false;
74
75 public IMesher mesher;
76 private float m_meshLOD;
77 public float MeshLOD
78 {
79 get { return m_meshLOD; }
80 }
81 private float m_sculptLOD;
82 public float SculptLOD
83 {
84 get { return m_sculptLOD; }
85 }
86
87 private int m_maxSubSteps;
88 private float m_fixedTimeStep;
89 private long m_simulationStep = 0;
90 public long SimulationStep { get { return m_simulationStep; } }
91
92 // A value of the time now so all the collision and update routines do not have to get their own
93 // Set to 'now' just before all the prims and actors are called for collisions and updates
94 private int m_simulationNowTime;
95 public int SimulationNowTime { get { return m_simulationNowTime; } }
96
97 private int m_maxCollisionsPerFrame;
98 private CollisionDesc[] m_collisionArray;
99 private GCHandle m_collisionArrayPinnedHandle;
100
101 private int m_maxUpdatesPerFrame;
102 private EntityProperties[] m_updateArray;
103 private GCHandle m_updateArrayPinnedHandle;
104
105 private bool _meshSculptedPrim = true; // cause scuplted prims to get meshed
106 private bool _forceSimplePrimMeshing = false; // if a cube or sphere, let Bullet do internal shapes
107
108 public const uint TERRAIN_ID = 0; // OpenSim senses terrain with a localID of zero
109 public const uint GROUNDPLANE_ID = 1;
110
111 public ConfigurationParameters Params
112 {
113 get { return m_params[0]; }
114 }
115 public Vector3 DefaultGravity
116 {
117 get { return new Vector3(0f, 0f, Params.gravity); }
118 }
119
120 private float m_maximumObjectMass;
121 public float MaximumObjectMass
122 {
123 get { return m_maximumObjectMass; }
124 }
125
126 public delegate void TaintCallback();
127 private List<TaintCallback> _taintedObjects;
128 private Object _taintLock = new Object();
129
130 // A pointer to an instance if this structure is passed to the C++ code
131 ConfigurationParameters[] m_params;
132 GCHandle m_paramsHandle;
133
134 private BulletSimAPI.DebugLogCallback m_DebugLogCallbackHandle;
135
136 public BSScene(string identifier)
137 {
138 m_initialized = false;
139 }
140
141 public override void Initialise(IMesher meshmerizer, IConfigSource config)
142 {
143 // Allocate pinned memory to pass parameters.
144 m_params = new ConfigurationParameters[1];
145 m_paramsHandle = GCHandle.Alloc(m_params, GCHandleType.Pinned);
146
147 // Set default values for physics parameters plus any overrides from the ini file
148 GetInitialParameterValues(config);
149
150 // allocate more pinned memory close to the above in an attempt to get the memory all together
151 m_collisionArray = new CollisionDesc[m_maxCollisionsPerFrame];
152 m_collisionArrayPinnedHandle = GCHandle.Alloc(m_collisionArray, GCHandleType.Pinned);
153 m_updateArray = new EntityProperties[m_maxUpdatesPerFrame];
154 m_updateArrayPinnedHandle = GCHandle.Alloc(m_updateArray, GCHandleType.Pinned);
155
156 // Get the version of the DLL
157 // TODO: this doesn't work yet. Something wrong with marshaling the returned string.
158 // BulletSimVersion = BulletSimAPI.GetVersion();
159 // m_log.WarnFormat("{0}: BulletSim.dll version='{1}'", LogHeader, BulletSimVersion);
160
161 // if Debug, enable logging from the unmanaged code
162 if (m_log.IsDebugEnabled)
163 {
164 m_log.DebugFormat("{0}: Initialize: Setting debug callback for unmanaged code", LogHeader);
165 m_DebugLogCallbackHandle = new BulletSimAPI.DebugLogCallback(BulletLogger);
166 BulletSimAPI.SetDebugLogCallback(m_DebugLogCallbackHandle);
167 }
168
169 _taintedObjects = new List<TaintCallback>();
170
171 mesher = meshmerizer;
172 // The bounding box for the simulated world
173 Vector3 worldExtent = new Vector3(Constants.RegionSize, Constants.RegionSize, 4096f);
174
175 // m_log.DebugFormat("{0}: Initialize: Calling BulletSimAPI.Initialize.", LogHeader);
176 m_worldID = BulletSimAPI.Initialize(worldExtent, m_paramsHandle.AddrOfPinnedObject(),
177 m_maxCollisionsPerFrame, m_collisionArrayPinnedHandle.AddrOfPinnedObject(),
178 m_maxUpdatesPerFrame, m_updateArrayPinnedHandle.AddrOfPinnedObject());
179
180 m_initialized = true;
181 }
182
183 // All default parameter values are set here. There should be no values set in the
184 // variable definitions.
185 private void GetInitialParameterValues(IConfigSource config)
186 {
187 ConfigurationParameters parms = new ConfigurationParameters();
188
189 _meshSculptedPrim = true; // mesh sculpted prims
190 _forceSimplePrimMeshing = false; // use complex meshing if called for
191
192 m_meshLOD = 8f;
193 m_sculptLOD = 32f;
194
195 m_maxSubSteps = 10;
196 m_fixedTimeStep = 1f / 60f;
197 m_maxCollisionsPerFrame = 2048;
198 m_maxUpdatesPerFrame = 2048;
199 m_maximumObjectMass = 10000.01f;
200
201 parms.defaultFriction = 0.5f;
202 parms.defaultDensity = 10.000006836f; // Aluminum g/cm3
203 parms.defaultRestitution = 0f;
204 parms.collisionMargin = 0.0f;
205 parms.gravity = -9.80665f;
206
207 parms.linearDamping = 0.0f;
208 parms.angularDamping = 0.0f;
209 parms.deactivationTime = 0.2f;
210 parms.linearSleepingThreshold = 0.8f;
211 parms.angularSleepingThreshold = 1.0f;
212 parms.ccdMotionThreshold = 0.5f; // set to zero to disable
213 parms.ccdSweptSphereRadius = 0.2f;
214
215 parms.terrainFriction = 0.5f;
216 parms.terrainHitFraction = 0.8f;
217 parms.terrainRestitution = 0f;
218 parms.avatarFriction = 0.0f;
219 parms.avatarDensity = 60f;
220 parms.avatarCapsuleRadius = 0.37f;
221 parms.avatarCapsuleHeight = 1.5f; // 2.140599f
222
223 if (config != null)
224 {
225 // If there are specifications in the ini file, use those values
226 // WHEN ADDING OR UPDATING THIS SECTION, BE SURE TO UPDATE OpenSimDefaults.ini
227 // ALSO REMEMBER TO UPDATE THE RUNTIME SETTING OF THE PARAMETERS.
228 IConfig pConfig = config.Configs["BulletSim"];
229 if (pConfig != null)
230 {
231 _meshSculptedPrim = pConfig.GetBoolean("MeshSculptedPrim", _meshSculptedPrim);
232 _forceSimplePrimMeshing = pConfig.GetBoolean("ForceSimplePrimMeshing", _forceSimplePrimMeshing);
233
234 m_meshLOD = pConfig.GetFloat("MeshLevelOfDetail", m_meshLOD);
235 m_sculptLOD = pConfig.GetFloat("SculptLevelOfDetail", m_sculptLOD);
236
237 m_maxSubSteps = pConfig.GetInt("MaxSubSteps", m_maxSubSteps);
238 m_fixedTimeStep = pConfig.GetFloat("FixedTimeStep", m_fixedTimeStep);
239 m_maxCollisionsPerFrame = pConfig.GetInt("MaxCollisionsPerFrame", m_maxCollisionsPerFrame);
240 m_maxUpdatesPerFrame = pConfig.GetInt("MaxUpdatesPerFrame", m_maxUpdatesPerFrame);
241 m_maximumObjectMass = pConfig.GetFloat("MaxObjectMass", m_maximumObjectMass);
242
243 parms.defaultFriction = pConfig.GetFloat("DefaultFriction", parms.defaultFriction);
244 parms.defaultDensity = pConfig.GetFloat("DefaultDensity", parms.defaultDensity);
245 parms.defaultRestitution = pConfig.GetFloat("DefaultRestitution", parms.defaultRestitution);
246 parms.collisionMargin = pConfig.GetFloat("CollisionMargin", parms.collisionMargin);
247 parms.gravity = pConfig.GetFloat("Gravity", parms.gravity);
248
249 parms.linearDamping = pConfig.GetFloat("LinearDamping", parms.linearDamping);
250 parms.angularDamping = pConfig.GetFloat("AngularDamping", parms.angularDamping);
251 parms.deactivationTime = pConfig.GetFloat("DeactivationTime", parms.deactivationTime);
252 parms.linearSleepingThreshold = pConfig.GetFloat("LinearSleepingThreshold", parms.linearSleepingThreshold);
253 parms.angularSleepingThreshold = pConfig.GetFloat("AngularSleepingThreshold", parms.angularSleepingThreshold);
254 parms.ccdMotionThreshold = pConfig.GetFloat("CcdMotionThreshold", parms.ccdMotionThreshold);
255 parms.ccdSweptSphereRadius = pConfig.GetFloat("CcdSweptSphereRadius", parms.ccdSweptSphereRadius);
256
257 parms.terrainFriction = pConfig.GetFloat("TerrainFriction", parms.terrainFriction);
258 parms.terrainHitFraction = pConfig.GetFloat("TerrainHitFraction", parms.terrainHitFraction);
259 parms.terrainRestitution = pConfig.GetFloat("TerrainRestitution", parms.terrainRestitution);
260 parms.avatarFriction = pConfig.GetFloat("AvatarFriction", parms.avatarFriction);
261 parms.avatarDensity = pConfig.GetFloat("AvatarDensity", parms.avatarDensity);
262 parms.avatarCapsuleRadius = pConfig.GetFloat("AvatarCapsuleRadius", parms.avatarCapsuleRadius);
263 parms.avatarCapsuleHeight = pConfig.GetFloat("AvatarCapsuleHeight", parms.avatarCapsuleHeight);
264 }
265 }
266 m_params[0] = parms;
267 }
268
269 // Called directly from unmanaged code so don't do much
270 private void BulletLogger(string msg)
271 {
272 m_log.Debug("[BULLETS UNMANAGED]:" + msg);
273 }
274
275 public override PhysicsActor AddAvatar(string avName, Vector3 position, Vector3 size, bool isFlying)
276 {
277 m_log.ErrorFormat("{0}: CALL TO AddAvatar in BSScene. NOT IMPLEMENTED", LogHeader);
278 return null;
279 }
280
281 public override PhysicsActor AddAvatar(uint localID, string avName, Vector3 position, Vector3 size, bool isFlying)
282 {
283 // m_log.DebugFormat("{0}: AddAvatar: {1}", LogHeader, avName);
284 BSCharacter actor = new BSCharacter(localID, avName, this, position, size, isFlying);
285 lock (m_avatars) m_avatars.Add(localID, actor);
286 return actor;
287 }
288
289 public override void RemoveAvatar(PhysicsActor actor)
290 {
291 // m_log.DebugFormat("{0}: RemoveAvatar", LogHeader);
292 if (actor is BSCharacter)
293 {
294 ((BSCharacter)actor).Destroy();
295 }
296 try
297 {
298 lock (m_avatars) m_avatars.Remove(actor.LocalID);
299 }
300 catch (Exception e)
301 {
302 m_log.WarnFormat("{0}: Attempt to remove avatar that is not in physics scene: {1}", LogHeader, e);
303 }
304 }
305
306 public override void RemovePrim(PhysicsActor prim)
307 {
308 // m_log.DebugFormat("{0}: RemovePrim", LogHeader);
309 if (prim is BSPrim)
310 {
311 ((BSPrim)prim).Destroy();
312 }
313 try
314 {
315 lock (m_prims) m_prims.Remove(prim.LocalID);
316 }
317 catch (Exception e)
318 {
319 m_log.WarnFormat("{0}: Attempt to remove prim that is not in physics scene: {1}", LogHeader, e);
320 }
321 }
322
323 public override PhysicsActor AddPrimShape(string primName, PrimitiveBaseShape pbs, Vector3 position,
324 Vector3 size, Quaternion rotation, bool isPhysical, uint localID)
325 {
326 // m_log.DebugFormat("{0}: AddPrimShape2: {1}", LogHeader, primName);
327 BSPrim prim = new BSPrim(localID, primName, this, position, size, rotation, pbs, isPhysical);
328 lock (m_prims) m_prims.Add(localID, prim);
329 return prim;
330 }
331
332 // This is a call from the simulator saying that some physical property has been updated.
333 // The BulletSim driver senses the changing of relevant properties so this taint
334 // information call is not needed.
335 public override void AddPhysicsActorTaint(PhysicsActor prim) { }
336
337 // Simulate one timestep
338 public override float Simulate(float timeStep)
339 {
340 int updatedEntityCount;
341 IntPtr updatedEntitiesPtr;
342 int collidersCount;
343 IntPtr collidersPtr;
344
345 // prevent simulation until we've been initialized
346 if (!m_initialized) return 10.0f;
347
348 // update the prim states while we know the physics engine is not busy
349 ProcessTaints();
350
351 // Some of the prims operate with special vehicle properties
352 ProcessVehicles(timeStep);
353 ProcessTaints(); // the vehicles might have added taints
354
355 // step the physical world one interval
356 m_simulationStep++;
357 int numSubSteps = BulletSimAPI.PhysicsStep(m_worldID, timeStep, m_maxSubSteps, m_fixedTimeStep,
358 out updatedEntityCount, out updatedEntitiesPtr, out collidersCount, out collidersPtr);
359
360 // Don't have to use the pointers passed back since we know it is the same pinned memory we passed in
361
362 // Get a value for 'now' so all the collision and update routines don't have to get their own
363 m_simulationNowTime = Util.EnvironmentTickCount();
364
365 // If there were collisions, process them by sending the event to the prim.
366 // Collisions must be processed before updates.
367 if (collidersCount > 0)
368 {
369 for (int ii = 0; ii < collidersCount; ii++)
370 {
371 uint cA = m_collisionArray[ii].aID;
372 uint cB = m_collisionArray[ii].bID;
373 Vector3 point = m_collisionArray[ii].point;
374 Vector3 normal = m_collisionArray[ii].normal;
375 SendCollision(cA, cB, point, normal, 0.01f);
376 SendCollision(cB, cA, point, -normal, 0.01f);
377 }
378 }
379
380 // If any of the objects had updated properties, tell the object it has been changed by the physics engine
381 if (updatedEntityCount > 0)
382 {
383 for (int ii = 0; ii < updatedEntityCount; ii++)
384 {
385 EntityProperties entprop = m_updateArray[ii];
386 // m_log.DebugFormat("{0}: entprop[{1}]: id={2}, pos={3}", LogHeader, ii, entprop.ID, entprop.Position);
387 BSCharacter actor;
388 if (m_avatars.TryGetValue(entprop.ID, out actor))
389 {
390 actor.UpdateProperties(entprop);
391 continue;
392 }
393 BSPrim prim;
394 if (m_prims.TryGetValue(entprop.ID, out prim))
395 {
396 prim.UpdateProperties(entprop);
397 }
398 }
399 }
400
401 // TODO: FIX THIS: fps calculation wrong. This calculation always returns about 1 in normal operation.
402 return timeStep / (numSubSteps * m_fixedTimeStep) * 1000f;
403 }
404
405 // Something has collided
406 private void SendCollision(uint localID, uint collidingWith, Vector3 collidePoint, Vector3 collideNormal, float penitration)
407 {
408 if (localID == TERRAIN_ID || localID == GROUNDPLANE_ID)
409 {
410 return; // don't send collisions to the terrain
411 }
412
413 ActorTypes type = ActorTypes.Prim;
414 if (collidingWith == TERRAIN_ID || collidingWith == GROUNDPLANE_ID)
415 type = ActorTypes.Ground;
416 else if (m_avatars.ContainsKey(collidingWith))
417 type = ActorTypes.Agent;
418
419 BSPrim prim;
420 if (m_prims.TryGetValue(localID, out prim)) {
421 prim.Collide(collidingWith, type, collidePoint, collideNormal, penitration);
422 return;
423 }
424 BSCharacter actor;
425 if (m_avatars.TryGetValue(localID, out actor)) {
426 actor.Collide(collidingWith, type, collidePoint, collideNormal, penitration);
427 return;
428 }
429 return;
430 }
431
432 public override void GetResults() { }
433
434 public override void SetTerrain(float[] heightMap) {
435 m_heightMap = heightMap;
436 this.TaintedObject(delegate()
437 {
438 BulletSimAPI.SetHeightmap(m_worldID, m_heightMap);
439 });
440 }
441
442 public float GetTerrainHeightAtXY(float tX, float tY)
443 {
444 return m_heightMap[((int)tX) * Constants.RegionSize + ((int)tY)];
445 }
446
447 public override void SetWaterLevel(float baseheight)
448 {
449 m_waterLevel = baseheight;
450 }
451 public float GetWaterLevel()
452 {
453 return m_waterLevel;
454 }
455
456 public override void DeleteTerrain()
457 {
458 m_log.DebugFormat("{0}: DeleteTerrain()", LogHeader);
459 }
460
461 public override void Dispose()
462 {
463 m_log.DebugFormat("{0}: Dispose()", LogHeader);
464 }
465
466 public override Dictionary<uint, float> GetTopColliders()
467 {
468 return new Dictionary<uint, float>();
469 }
470
471 public override bool IsThreaded { get { return false; } }
472
473 /// <summary>
474 /// Routine to figure out if we need to mesh this prim with our mesher
475 /// </summary>
476 /// <param name="pbs"></param>
477 /// <returns>true if the prim needs meshing</returns>
478 public bool NeedsMeshing(PrimitiveBaseShape pbs)
479 {
480 // most of this is redundant now as the mesher will return null if it cant mesh a prim
481 // but we still need to check for sculptie meshing being enabled so this is the most
482 // convenient place to do it for now...
483
484 // int iPropertiesNotSupportedDefault = 0;
485
486 if (pbs.SculptEntry && !_meshSculptedPrim)
487 {
488 // Render sculpties as boxes
489 return false;
490 }
491
492 // if it's a standard box or sphere with no cuts, hollows, twist or top shear, return false since Bullet
493 // can use an internal representation for the prim
494 if (!_forceSimplePrimMeshing)
495 {
496 if ((pbs.ProfileShape == ProfileShape.Square && pbs.PathCurve == (byte)Extrusion.Straight)
497 || (pbs.ProfileShape == ProfileShape.HalfCircle && pbs.PathCurve == (byte)Extrusion.Curve1
498 && pbs.Scale.X == pbs.Scale.Y && pbs.Scale.Y == pbs.Scale.Z))
499 {
500
501 if (pbs.ProfileBegin == 0 && pbs.ProfileEnd == 0
502 && pbs.ProfileHollow == 0
503 && pbs.PathTwist == 0 && pbs.PathTwistBegin == 0
504 && pbs.PathBegin == 0 && pbs.PathEnd == 0
505 && pbs.PathTaperX == 0 && pbs.PathTaperY == 0
506 && pbs.PathScaleX == 100 && pbs.PathScaleY == 100
507 && pbs.PathShearX == 0 && pbs.PathShearY == 0)
508 {
509 return false;
510 }
511 }
512 }
513
514 /* TODO: verify that the mesher will now do all these shapes
515 if (pbs.ProfileHollow != 0)
516 iPropertiesNotSupportedDefault++;
517
518 if ((pbs.PathBegin != 0) || pbs.PathEnd != 0)
519 iPropertiesNotSupportedDefault++;
520
521 if ((pbs.PathTwistBegin != 0) || (pbs.PathTwist != 0))
522 iPropertiesNotSupportedDefault++;
523
524 if ((pbs.ProfileBegin != 0) || pbs.ProfileEnd != 0)
525 iPropertiesNotSupportedDefault++;
526
527 if ((pbs.PathScaleX != 100) || (pbs.PathScaleY != 100))
528 iPropertiesNotSupportedDefault++;
529
530 if ((pbs.PathShearX != 0) || (pbs.PathShearY != 0))
531 iPropertiesNotSupportedDefault++;
532
533 if (pbs.ProfileShape == ProfileShape.Circle && pbs.PathCurve == (byte)Extrusion.Straight)
534 iPropertiesNotSupportedDefault++;
535
536 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))
537 iPropertiesNotSupportedDefault++;
538
539 if (pbs.ProfileShape == ProfileShape.HalfCircle && pbs.PathCurve == (byte) Extrusion.Curve1)
540 iPropertiesNotSupportedDefault++;
541
542 // test for torus
543 if ((pbs.ProfileCurve & 0x07) == (byte)ProfileShape.Square)
544 {
545 if (pbs.PathCurve == (byte)Extrusion.Curve1)
546 {
547 iPropertiesNotSupportedDefault++;
548 }
549 }
550 else if ((pbs.ProfileCurve & 0x07) == (byte)ProfileShape.Circle)
551 {
552 if (pbs.PathCurve == (byte)Extrusion.Straight)
553 {
554 iPropertiesNotSupportedDefault++;
555 }
556 // ProfileCurve seems to combine hole shape and profile curve so we need to only compare against the lower 3 bits
557 else if (pbs.PathCurve == (byte)Extrusion.Curve1)
558 {
559 iPropertiesNotSupportedDefault++;
560 }
561 }
562 else if ((pbs.ProfileCurve & 0x07) == (byte)ProfileShape.HalfCircle)
563 {
564 if (pbs.PathCurve == (byte)Extrusion.Curve1 || pbs.PathCurve == (byte)Extrusion.Curve2)
565 {
566 iPropertiesNotSupportedDefault++;
567 }
568 }
569 else if ((pbs.ProfileCurve & 0x07) == (byte)ProfileShape.EquilateralTriangle)
570 {
571 if (pbs.PathCurve == (byte)Extrusion.Straight)
572 {
573 iPropertiesNotSupportedDefault++;
574 }
575 else if (pbs.PathCurve == (byte)Extrusion.Curve1)
576 {
577 iPropertiesNotSupportedDefault++;
578 }
579 }
580 if (iPropertiesNotSupportedDefault == 0)
581 {
582 return false;
583 }
584 */
585 return true;
586 }
587
588 // The calls to the PhysicsActors can't directly call into the physics engine
589 // because it might be busy. We we delay changes to a known time.
590 // We rely on C#'s closure to save and restore the context for the delegate.
591 public void TaintedObject(TaintCallback callback)
592 {
593 lock (_taintLock)
594 _taintedObjects.Add(callback);
595 return;
596 }
597
598 // When someone tries to change a property on a BSPrim or BSCharacter, the object queues
599 // a callback into itself to do the actual property change. That callback is called
600 // here just before the physics engine is called to step the simulation.
601 public void ProcessTaints()
602 {
603 if (_taintedObjects.Count > 0) // save allocating new list if there is nothing to process
604 {
605 // swizzle a new list into the list location so we can process what's there
606 List<TaintCallback> oldList;
607 lock (_taintLock)
608 {
609 oldList = _taintedObjects;
610 _taintedObjects = new List<TaintCallback>();
611 }
612
613 foreach (TaintCallback callback in oldList)
614 {
615 try
616 {
617 callback();
618 }
619 catch (Exception e)
620 {
621 m_log.ErrorFormat("{0}: ProcessTaints: Exception: {1}", LogHeader, e);
622 }
623 }
624 oldList.Clear();
625 }
626 }
627
628 #region Vehicles
629 // Make so the scene will call this prim for vehicle actions each tick.
630 // Safe to call if prim is already in the vehicle list.
631 public void AddVehiclePrim(BSPrim vehicle)
632 {
633 lock (m_vehicles)
634 {
635 if (!m_vehicles.Contains(vehicle))
636 {
637 m_vehicles.Add(vehicle);
638 }
639 }
640 }
641
642 // Remove a prim from our list of vehicles.
643 // Safe to call if the prim is not in the vehicle list.
644 public void RemoveVehiclePrim(BSPrim vehicle)
645 {
646 lock (m_vehicles)
647 {
648 if (m_vehicles.Contains(vehicle))
649 {
650 m_vehicles.Remove(vehicle);
651 }
652 }
653 }
654
655 // Some prims have extra vehicle actions
656 // no locking because only called when physics engine is not busy
657 private void ProcessVehicles(float timeStep)
658 {
659 foreach (BSPrim prim in m_vehicles)
660 {
661 prim.StepVehicle(timeStep);
662 }
663 }
664 #endregion Vehicles
665
666 #region Runtime settable parameters
667 public static PhysParameterEntry[] SettableParameters = new PhysParameterEntry[]
668 {
669 new PhysParameterEntry("MeshLOD", "Level of detail to render meshes (32, 16, 8 or 4. 32=most detailed)"),
670 new PhysParameterEntry("SculptLOD", "Level of detail to render sculpties (32, 16, 8 or 4. 32=most detailed)"),
671 new PhysParameterEntry("MaxSubStep", "In simulation step, maximum number of substeps"),
672 new PhysParameterEntry("FixedTimeStep", "In simulation step, seconds of one substep (1/60)"),
673 new PhysParameterEntry("MaxObjectMass", "Maximum object mass (10000.01)"),
674
675 new PhysParameterEntry("DefaultFriction", "Friction factor used on new objects"),
676 new PhysParameterEntry("DefaultDensity", "Density for new objects" ),
677 new PhysParameterEntry("DefaultRestitution", "Bouncyness of an object" ),
678 // new PhysParameterEntry("CollisionMargin", "Margin around objects before collisions are calculated (must be zero!!)" ),
679 new PhysParameterEntry("Gravity", "Vertical force of gravity (negative means down)" ),
680
681 new PhysParameterEntry("LinearDamping", "Factor to damp linear movement per second (0.0 - 1.0)" ),
682 new PhysParameterEntry("AngularDamping", "Factor to damp angular movement per second (0.0 - 1.0)" ),
683 new PhysParameterEntry("DeactivationTime", "Seconds before considering an object potentially static" ),
684 new PhysParameterEntry("LinearSleepingThreshold", "Seconds to measure linear movement before considering static" ),
685 new PhysParameterEntry("AngularSleepingThreshold", "Seconds to measure angular movement before considering static" ),
686 // new PhysParameterEntry("CcdMotionThreshold", "" ),
687 // new PhysParameterEntry("CcdSweptSphereRadius", "" ),
688
689 new PhysParameterEntry("TerrainFriction", "Factor to reduce movement against terrain surface" ),
690 new PhysParameterEntry("TerrainHitFraction", "Distance to measure hit collisions" ),
691 new PhysParameterEntry("TerrainRestitution", "Bouncyness" ),
692 new PhysParameterEntry("AvatarFriction", "Factor to reduce movement against an avatar. Changed on avatar recreation." ),
693 new PhysParameterEntry("AvatarDensity", "Density of an avatar. Changed on avatar recreation." ),
694 new PhysParameterEntry("AvatarRestitution", "Bouncyness. Changed on avatar recreation." ),
695 new PhysParameterEntry("AvatarCapsuleRadius", "Radius of space around an avatar" ),
696 new PhysParameterEntry("AvatarCapsuleHeight", "Default height of space around avatar" )
697 };
698
699 #region IPhysicsParameters
700 // Get the list of parameters this physics engine supports
701 public PhysParameterEntry[] GetParameterList()
702 {
703 return SettableParameters;
704 }
705
706 // Set parameter on a specific or all instances.
707 // Return 'false' if not able to set the parameter.
708 // Setting the value in the m_params block will change the value the physics engine
709 // will use the next time since it's pinned and shared memory.
710 // Some of the values require calling into the physics engine to get the new
711 // value activated ('terrainFriction' for instance).
712 public bool SetPhysicsParameter(string parm, float val, uint localID)
713 {
714 bool ret = true;
715 string lparm = parm.ToLower();
716 switch (lparm)
717 {
718 case "meshlod": m_meshLOD = (int)val; break;
719 case "sculptlod": m_sculptLOD = (int)val; break;
720 case "maxsubstep": m_maxSubSteps = (int)val; break;
721 case "fixedtimestep": m_fixedTimeStep = val; break;
722 case "maxobjectmass": m_maximumObjectMass = val; break;
723
724 case "defaultfriction": m_params[0].defaultFriction = val; break;
725 case "defaultdensity": m_params[0].defaultDensity = val; break;
726 case "defaultrestitution": m_params[0].defaultRestitution = val; break;
727 case "collisionmargin": m_params[0].collisionMargin = val; break;
728 case "gravity": m_params[0].gravity = val; TaintedUpdateParameter(lparm, PhysParameterEntry.APPLY_TO_NONE, val); break;
729
730 case "lineardamping": UpdateParameterPrims(ref m_params[0].linearDamping, lparm, localID, val); break;
731 case "angulardamping": UpdateParameterPrims(ref m_params[0].angularDamping, lparm, localID, val); break;
732 case "deactivationtime": UpdateParameterPrims(ref m_params[0].deactivationTime, lparm, localID, val); break;
733 case "linearsleepingthreshold": UpdateParameterPrims(ref m_params[0].linearSleepingThreshold, lparm, localID, val); break;
734 case "angularsleepingthreshold": UpdateParameterPrims(ref m_params[0].angularDamping, lparm, localID, val); break;
735 case "ccdmotionthreshold": UpdateParameterPrims(ref m_params[0].ccdMotionThreshold, lparm, localID, val); break;
736 case "ccdsweptsphereradius": UpdateParameterPrims(ref m_params[0].ccdSweptSphereRadius, lparm, localID, val); break;
737
738 // set a terrain physical feature and cause terrain to be recalculated
739 case "terrainfriction": m_params[0].terrainFriction = val; TaintedUpdateParameter("terrain", 0, val); break;
740 case "terrainhitfraction": m_params[0].terrainHitFraction = val; TaintedUpdateParameter("terrain", 0, val); break;
741 case "terrainrestitution": m_params[0].terrainRestitution = val; TaintedUpdateParameter("terrain", 0, val); break;
742 // set an avatar physical feature and cause avatar(s) to be recalculated
743 case "avatarfriction": UpdateParameterAvatars(ref m_params[0].avatarFriction, "avatar", localID, val); break;
744 case "avatardensity": UpdateParameterAvatars(ref m_params[0].avatarDensity, "avatar", localID, val); break;
745 case "avatarrestitution": UpdateParameterAvatars(ref m_params[0].avatarRestitution, "avatar", localID, val); break;
746 case "avatarcapsuleradius": UpdateParameterAvatars(ref m_params[0].avatarCapsuleRadius, "avatar", localID, val); break;
747 case "avatarcapsuleheight": UpdateParameterAvatars(ref m_params[0].avatarCapsuleHeight, "avatar", localID, val); break;
748
749 default: ret = false; break;
750 }
751 return ret;
752 }
753
754 // check to see if we are updating a parameter for a particular or all of the prims
755 private void UpdateParameterPrims(ref float loc, string parm, uint localID, float val)
756 {
757 List<uint> operateOn;
758 lock (m_prims) operateOn = new List<uint>(m_prims.Keys);
759 UpdateParameterSet(operateOn, ref loc, parm, localID, val);
760 }
761
762 // check to see if we are updating a parameter for a particular or all of the avatars
763 private void UpdateParameterAvatars(ref float loc, string parm, uint localID, float val)
764 {
765 List<uint> operateOn;
766 lock (m_avatars) operateOn = new List<uint>(m_avatars.Keys);
767 UpdateParameterSet(operateOn, ref loc, parm, localID, val);
768 }
769
770 // update all the localIDs specified
771 // If the local ID is APPLY_TO_NONE, just change the default value
772 // If the localID is APPLY_TO_ALL change the default value and apply the new value to all the lIDs
773 // If the localID is a specific object, apply the parameter change to only that object
774 private void UpdateParameterSet(List<uint> lIDs, ref float defaultLoc, string parm, uint localID, float val)
775 {
776 switch (localID)
777 {
778 case PhysParameterEntry.APPLY_TO_NONE:
779 defaultLoc = val; // setting only the default value
780 break;
781 case PhysParameterEntry.APPLY_TO_ALL:
782 defaultLoc = val; // setting ALL also sets the default value
783 List<uint> objectIDs = lIDs;
784 string xparm = parm.ToLower();
785 float xval = val;
786 TaintedObject(delegate() {
787 foreach (uint lID in objectIDs)
788 {
789 BulletSimAPI.UpdateParameter(m_worldID, lID, xparm, xval);
790 }
791 });
792 break;
793 default:
794 // setting only one localID
795 TaintedUpdateParameter(parm, localID, val);
796 break;
797 }
798 }
799
800 // schedule the actual updating of the paramter to when the phys engine is not busy
801 private void TaintedUpdateParameter(string parm, uint localID, float val)
802 {
803 uint xlocalID = localID;
804 string xparm = parm.ToLower();
805 float xval = val;
806 TaintedObject(delegate() {
807 BulletSimAPI.UpdateParameter(m_worldID, xlocalID, xparm, xval);
808 });
809 }
810
811 // Get parameter.
812 // Return 'false' if not able to get the parameter.
813 public bool GetPhysicsParameter(string parm, out float value)
814 {
815 float val = 0f;
816 bool ret = true;
817 switch (parm.ToLower())
818 {
819 case "meshlod": val = (float)m_meshLOD; break;
820 case "sculptlod": val = (float)m_sculptLOD; break;
821 case "maxsubstep": val = (float)m_maxSubSteps; break;
822 case "fixedtimestep": val = m_fixedTimeStep; break;
823 case "maxobjectmass": val = m_maximumObjectMass; break;
824
825 case "defaultfriction": val = m_params[0].defaultFriction; break;
826 case "defaultdensity": val = m_params[0].defaultDensity; break;
827 case "defaultrestitution": val = m_params[0].defaultRestitution; break;
828 case "collisionmargin": val = m_params[0].collisionMargin; break;
829 case "gravity": val = m_params[0].gravity; break;
830
831 case "lineardamping": val = m_params[0].linearDamping; break;
832 case "angulardamping": val = m_params[0].angularDamping; break;
833 case "deactivationtime": val = m_params[0].deactivationTime; break;
834 case "linearsleepingthreshold": val = m_params[0].linearSleepingThreshold; break;
835 case "angularsleepingthreshold": val = m_params[0].angularDamping; break;
836 case "ccdmotionthreshold": val = m_params[0].ccdMotionThreshold; break;
837 case "ccdsweptsphereradius": val = m_params[0].ccdSweptSphereRadius; break;
838
839 case "terrainfriction": val = m_params[0].terrainFriction; break;
840 case "terrainhitfraction": val = m_params[0].terrainHitFraction; break;
841 case "terrainrestitution": val = m_params[0].terrainRestitution; break;
842
843 case "avatarfriction": val = m_params[0].avatarFriction; break;
844 case "avatardensity": val = m_params[0].avatarDensity; break;
845 case "avatarrestitution": val = m_params[0].avatarRestitution; break;
846 case "avatarcapsuleradius": val = m_params[0].avatarCapsuleRadius; break;
847 case "avatarcapsuleheight": val = m_params[0].avatarCapsuleHeight; break;
848 default: ret = false; break;
849
850 }
851 value = val;
852 return ret;
853 }
854
855 #endregion IPhysicsParameters
856
857 #endregion Runtime settable parameters
858
859}
860}
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BulletSimAPI.cs b/OpenSim/Region/Physics/BulletSPlugin/BulletSimAPI.cs
new file mode 100644
index 0000000..a610c8d
--- /dev/null
+++ b/OpenSim/Region/Physics/BulletSPlugin/BulletSimAPI.cs
@@ -0,0 +1,257 @@
1/*
2 * Copyright (c) Contributors, http://opensimulator.org/
3 * See CONTRIBUTORS.TXT for a full list of copyright holders.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 * * Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * * Redistributions in binary form must reproduce the above copyrightD
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 * * Neither the name of the OpenSimulator Project nor the
13 * names of its contributors may be used to endorse or promote products
14 * derived from this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
17 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19 * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
20 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
27using System;
28using System.Runtime.InteropServices;
29using System.Security;
30using System.Text;
31using OpenMetaverse;
32
33namespace OpenSim.Region.Physics.BulletSPlugin {
34
35[StructLayout(LayoutKind.Sequential)]
36public struct ConvexHull
37{
38 Vector3 Offset;
39 int VertexCount;
40 Vector3[] Vertices;
41}
42[StructLayout(LayoutKind.Sequential)]
43public struct ShapeData
44{
45 public enum PhysicsShapeType
46 {
47 SHAPE_AVATAR = 0,
48 SHAPE_BOX = 1,
49 SHAPE_CONE = 2,
50 SHAPE_CYLINDER = 3,
51 SHAPE_SPHERE = 4,
52 SHAPE_MESH = 5,
53 SHAPE_HULL = 6
54 };
55 public uint ID;
56 public PhysicsShapeType Type;
57 public Vector3 Position;
58 public Quaternion Rotation;
59 public Vector3 Velocity;
60 public Vector3 Scale;
61 public float Mass;
62 public float Buoyancy;
63 public System.UInt64 HullKey;
64 public System.UInt64 MeshKey;
65 public float Friction;
66 public float Restitution;
67 public int Collidable;
68 public int Static; // true if a static object. Otherwise gravity, etc.
69
70 // note that bools are passed as ints since bool size changes by language and architecture
71 public const int numericTrue = 1;
72 public const int numericFalse = 0;
73}
74[StructLayout(LayoutKind.Sequential)]
75public struct SweepHit
76{
77 public uint ID;
78 public float Fraction;
79 public Vector3 Normal;
80 public Vector3 Point;
81}
82[StructLayout(LayoutKind.Sequential)]
83public struct RaycastHit
84{
85 public uint ID;
86 public float Fraction;
87 public Vector3 Normal;
88}
89[StructLayout(LayoutKind.Sequential)]
90public struct CollisionDesc
91{
92 public uint aID;
93 public uint bID;
94 public Vector3 point;
95 public Vector3 normal;
96}
97[StructLayout(LayoutKind.Sequential)]
98public struct EntityProperties
99{
100 public uint ID;
101 public Vector3 Position;
102 public Quaternion Rotation;
103 public Vector3 Velocity;
104 public Vector3 Acceleration;
105 public Vector3 RotationalVelocity;
106}
107
108// Format of this structure must match the definition in the C++ code
109[StructLayout(LayoutKind.Sequential)]
110public struct ConfigurationParameters
111{
112 public float defaultFriction;
113 public float defaultDensity;
114 public float defaultRestitution;
115 public float collisionMargin;
116 public float gravity;
117
118 public float linearDamping;
119 public float angularDamping;
120 public float deactivationTime;
121 public float linearSleepingThreshold;
122 public float angularSleepingThreshold;
123 public float ccdMotionThreshold;
124 public float ccdSweptSphereRadius;
125
126 public float terrainFriction;
127 public float terrainHitFraction;
128 public float terrainRestitution;
129 public float avatarFriction;
130 public float avatarDensity;
131 public float avatarRestitution;
132 public float avatarCapsuleRadius;
133 public float avatarCapsuleHeight;
134
135 public const float numericTrue = 1f;
136 public const float numericFalse = 0f;
137}
138
139static class BulletSimAPI {
140
141[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
142[return: MarshalAs(UnmanagedType.LPStr)]
143public static extern string GetVersion();
144
145[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
146public static extern uint Initialize(Vector3 maxPosition, IntPtr parms,
147 int maxCollisions, IntPtr collisionArray,
148 int maxUpdates, IntPtr updateArray);
149
150[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
151public static extern bool UpdateParameter(uint worldID, uint localID,
152 [MarshalAs(UnmanagedType.LPStr)]string paramCode, float value);
153
154[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
155public static extern void SetHeightmap(uint worldID, [MarshalAs(UnmanagedType.LPArray)] float[] heightMap);
156
157[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
158public static extern void Shutdown(uint worldID);
159
160
161[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
162public static extern int PhysicsStep(uint worldID, float timeStep, int maxSubSteps, float fixedTimeStep,
163 out int updatedEntityCount,
164 out IntPtr updatedEntitiesPtr,
165 out int collidersCount,
166 out IntPtr collidersPtr);
167
168[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
169public static extern bool CreateHull(uint worldID, System.UInt64 meshKey,
170 int hullCount, [MarshalAs(UnmanagedType.LPArray)] float[] hulls
171 );
172
173[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
174public static extern bool CreateMesh(uint worldID, System.UInt64 meshKey,
175 int indexCount, [MarshalAs(UnmanagedType.LPArray)] int[] indices,
176 int verticesCount, [MarshalAs(UnmanagedType.LPArray)] float[] vertices
177 );
178
179[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
180public static extern bool DestroyHull(uint worldID, System.UInt64 meshKey);
181
182[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
183public static extern bool DestroyMesh(uint worldID, System.UInt64 meshKey);
184
185[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
186public static extern bool CreateObject(uint worldID, ShapeData shapeData);
187
188[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
189public static extern void CreateLinkset(uint worldID, int objectCount, ShapeData[] shapeDatas);
190
191[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
192public static extern void AddConstraint(uint worldID, uint id1, uint id2,
193 Vector3 frame1, Quaternion frame1rot,
194 Vector3 frame2, Quaternion frame2rot,
195 Vector3 lowLinear, Vector3 hiLinear, Vector3 lowAngular, Vector3 hiAngular);
196
197[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
198public static extern bool RemoveConstraintByID(uint worldID, uint id1);
199
200[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
201public static extern bool RemoveConstraint(uint worldID, uint id1, uint id2);
202
203[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
204public static extern Vector3 GetObjectPosition(uint WorldID, uint id);
205
206[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
207public static extern bool SetObjectTranslation(uint worldID, uint id, Vector3 position, Quaternion rotation);
208
209[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
210public static extern bool SetObjectVelocity(uint worldID, uint id, Vector3 velocity);
211
212[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
213public static extern bool SetObjectAngularVelocity(uint worldID, uint id, Vector3 angularVelocity);
214
215[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
216public static extern bool SetObjectForce(uint worldID, uint id, Vector3 force);
217
218[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
219public static extern bool SetObjectScaleMass(uint worldID, uint id, Vector3 scale, float mass, bool isDynamic);
220
221[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
222public static extern bool SetObjectCollidable(uint worldID, uint id, bool phantom);
223
224[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
225public static extern bool SetObjectDynamic(uint worldID, uint id, bool isDynamic, float mass);
226
227[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
228public static extern bool SetObjectGhost(uint worldID, uint id, bool ghostly);
229
230[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
231public static extern bool SetObjectProperties(uint worldID, uint id, bool isStatic, bool isSolid, bool genCollisions, float mass);
232
233[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
234public static extern bool SetObjectBuoyancy(uint worldID, uint id, float buoyancy);
235
236[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
237public static extern bool HasObject(uint worldID, uint id);
238
239[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
240public static extern bool DestroyObject(uint worldID, uint id);
241
242[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
243public static extern SweepHit ConvexSweepTest(uint worldID, uint id, Vector3 to, float extraMargin);
244
245[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
246public static extern RaycastHit RayTest(uint worldID, uint id, Vector3 from, Vector3 to);
247
248[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
249public static extern Vector3 RecoverFromPenetration(uint worldID, uint id);
250
251// Log a debug message
252[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
253public delegate void DebugLogCallback([MarshalAs(UnmanagedType.LPStr)]string msg);
254[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
255public static extern void SetDebugLogCallback(DebugLogCallback callback);
256}
257}
diff --git a/OpenSim/Region/Physics/ConvexDecompositionDotNet/CTri.cs b/OpenSim/Region/Physics/ConvexDecompositionDotNet/CTri.cs
new file mode 100644
index 0000000..4d84c44
--- /dev/null
+++ b/OpenSim/Region/Physics/ConvexDecompositionDotNet/CTri.cs
@@ -0,0 +1,341 @@
1/* The MIT License
2 *
3 * Copyright (c) 2010 Intel Corporation.
4 * All rights reserved.
5 *
6 * Based on the convexdecomposition library from
7 * <http://codesuppository.googlecode.com> by John W. Ratcliff and Stan Melax.
8 *
9 * Permission is hereby granted, free of charge, to any person obtaining a copy
10 * of this software and associated documentation files (the "Software"), to deal
11 * in the Software without restriction, including without limitation the rights
12 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
13 * copies of the Software, and to permit persons to whom the Software is
14 * furnished to do so, subject to the following conditions:
15 *
16 * The above copyright notice and this permission notice shall be included in
17 * all copies or substantial portions of the Software.
18 *
19 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
20 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
21 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
22 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
23 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
24 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
25 * THE SOFTWARE.
26 */
27
28using System;
29using System.Collections.Generic;
30
31namespace OpenSim.Region.Physics.ConvexDecompositionDotNet
32{
33 public class Wpoint
34 {
35 public float3 mPoint;
36 public float mWeight;
37
38 public Wpoint(float3 p, float w)
39 {
40 mPoint = p;
41 mWeight = w;
42 }
43 }
44
45 public class CTri
46 {
47 private const int WSCALE = 4;
48
49 public float3 mP1;
50 public float3 mP2;
51 public float3 mP3;
52 public float3 mNear1;
53 public float3 mNear2;
54 public float3 mNear3;
55 public float3 mNormal;
56 public float mPlaneD;
57 public float mConcavity;
58 public float mC1;
59 public float mC2;
60 public float mC3;
61 public int mI1;
62 public int mI2;
63 public int mI3;
64 public int mProcessed; // already been added...
65
66 public CTri(float3 p1, float3 p2, float3 p3, int i1, int i2, int i3)
67 {
68 mProcessed = 0;
69 mI1 = i1;
70 mI2 = i2;
71 mI3 = i3;
72
73 mP1 = new float3(p1);
74 mP2 = new float3(p2);
75 mP3 = new float3(p3);
76
77 mNear1 = new float3();
78 mNear2 = new float3();
79 mNear3 = new float3();
80
81 mNormal = new float3();
82 mPlaneD = mNormal.ComputePlane(mP1, mP2, mP3);
83 }
84
85 public float Facing(CTri t)
86 {
87 return float3.dot(mNormal, t.mNormal);
88 }
89
90 public bool clip(float3 start, ref float3 end)
91 {
92 float3 sect = new float3();
93 bool hit = lineIntersectsTriangle(start, end, mP1, mP2, mP3, ref sect);
94
95 if (hit)
96 end = sect;
97 return hit;
98 }
99
100 public bool Concave(float3 p, ref float distance, ref float3 n)
101 {
102 n.NearestPointInTriangle(p, mP1, mP2, mP3);
103 distance = p.Distance(n);
104 return true;
105 }
106
107 public void addTri(int[] indices, int i1, int i2, int i3, ref int tcount)
108 {
109 indices[tcount * 3 + 0] = i1;
110 indices[tcount * 3 + 1] = i2;
111 indices[tcount * 3 + 2] = i3;
112 tcount++;
113 }
114
115 public float getVolume()
116 {
117 int[] indices = new int[8 * 3];
118
119 int tcount = 0;
120
121 addTri(indices, 0, 1, 2, ref tcount);
122 addTri(indices, 3, 4, 5, ref tcount);
123
124 addTri(indices, 0, 3, 4, ref tcount);
125 addTri(indices, 0, 4, 1, ref tcount);
126
127 addTri(indices, 1, 4, 5, ref tcount);
128 addTri(indices, 1, 5, 2, ref tcount);
129
130 addTri(indices, 0, 3, 5, ref tcount);
131 addTri(indices, 0, 5, 2, ref tcount);
132
133 List<float3> vertices = new List<float3> { mP1, mP2, mP3, mNear1, mNear2, mNear3 };
134 List<int> indexList = new List<int>(indices);
135
136 float v = Concavity.computeMeshVolume(vertices, indexList);
137 return v;
138 }
139
140 public float raySect(float3 p, float3 dir, ref float3 sect)
141 {
142 float4 plane = new float4();
143
144 plane.x = mNormal.x;
145 plane.y = mNormal.y;
146 plane.z = mNormal.z;
147 plane.w = mPlaneD;
148
149 float3 dest = p + dir * 100000f;
150
151 intersect(p, dest, ref sect, plane);
152
153 return sect.Distance(p); // return the intersection distance
154 }
155
156 public float planeDistance(float3 p)
157 {
158 float4 plane = new float4();
159
160 plane.x = mNormal.x;
161 plane.y = mNormal.y;
162 plane.z = mNormal.z;
163 plane.w = mPlaneD;
164
165 return DistToPt(p, plane);
166 }
167
168 public bool samePlane(CTri t)
169 {
170 const float THRESH = 0.001f;
171 float dd = Math.Abs(t.mPlaneD - mPlaneD);
172 if (dd > THRESH)
173 return false;
174 dd = Math.Abs(t.mNormal.x - mNormal.x);
175 if (dd > THRESH)
176 return false;
177 dd = Math.Abs(t.mNormal.y - mNormal.y);
178 if (dd > THRESH)
179 return false;
180 dd = Math.Abs(t.mNormal.z - mNormal.z);
181 if (dd > THRESH)
182 return false;
183 return true;
184 }
185
186 public bool hasIndex(int i)
187 {
188 if (i == mI1 || i == mI2 || i == mI3)
189 return true;
190 return false;
191 }
192
193 public bool sharesEdge(CTri t)
194 {
195 bool ret = false;
196 uint count = 0;
197
198 if (t.hasIndex(mI1))
199 count++;
200 if (t.hasIndex(mI2))
201 count++;
202 if (t.hasIndex(mI3))
203 count++;
204
205 if (count >= 2)
206 ret = true;
207
208 return ret;
209 }
210
211 public float area()
212 {
213 float a = mConcavity * mP1.Area(mP2, mP3);
214 return a;
215 }
216
217 public void addWeighted(List<Wpoint> list)
218 {
219 Wpoint p1 = new Wpoint(mP1, mC1);
220 Wpoint p2 = new Wpoint(mP2, mC2);
221 Wpoint p3 = new Wpoint(mP3, mC3);
222
223 float3 d1 = mNear1 - mP1;
224 float3 d2 = mNear2 - mP2;
225 float3 d3 = mNear3 - mP3;
226
227 d1 *= WSCALE;
228 d2 *= WSCALE;
229 d3 *= WSCALE;
230
231 d1 = d1 + mP1;
232 d2 = d2 + mP2;
233 d3 = d3 + mP3;
234
235 Wpoint p4 = new Wpoint(d1, mC1);
236 Wpoint p5 = new Wpoint(d2, mC2);
237 Wpoint p6 = new Wpoint(d3, mC3);
238
239 list.Add(p1);
240 list.Add(p2);
241 list.Add(p3);
242
243 list.Add(p4);
244 list.Add(p5);
245 list.Add(p6);
246 }
247
248 private static float DistToPt(float3 p, float4 plane)
249 {
250 float x = p.x;
251 float y = p.y;
252 float z = p.z;
253 float d = x*plane.x + y*plane.y + z*plane.z + plane.w;
254 return d;
255 }
256
257 private static void intersect(float3 p1, float3 p2, ref float3 split, float4 plane)
258 {
259 float dp1 = DistToPt(p1, plane);
260
261 float3 dir = new float3();
262 dir.x = p2[0] - p1[0];
263 dir.y = p2[1] - p1[1];
264 dir.z = p2[2] - p1[2];
265
266 float dot1 = dir[0] * plane[0] + dir[1] * plane[1] + dir[2] * plane[2];
267 float dot2 = dp1 - plane[3];
268
269 float t = -(plane[3] + dot2) / dot1;
270
271 split.x = (dir[0] * t) + p1[0];
272 split.y = (dir[1] * t) + p1[1];
273 split.z = (dir[2] * t) + p1[2];
274 }
275
276 private static bool rayIntersectsTriangle(float3 p, float3 d, float3 v0, float3 v1, float3 v2, out float t)
277 {
278 t = 0f;
279
280 float3 e1, e2, h, s, q;
281 float a, f, u, v;
282
283 e1 = v1 - v0;
284 e2 = v2 - v0;
285 h = float3.cross(d, e2);
286 a = float3.dot(e1, h);
287
288 if (a > -0.00001f && a < 0.00001f)
289 return false;
290
291 f = 1f / a;
292 s = p - v0;
293 u = f * float3.dot(s, h);
294
295 if (u < 0.0f || u > 1.0f)
296 return false;
297
298 q = float3.cross(s, e1);
299 v = f * float3.dot(d, q);
300 if (v < 0.0f || u + v > 1.0f)
301 return false;
302
303 // at this stage we can compute t to find out where
304 // the intersection point is on the line
305 t = f * float3.dot(e2, q);
306 if (t > 0f) // ray intersection
307 return true;
308 else // this means that there is a line intersection but not a ray intersection
309 return false;
310 }
311
312 private static bool lineIntersectsTriangle(float3 rayStart, float3 rayEnd, float3 p1, float3 p2, float3 p3, ref float3 sect)
313 {
314 float3 dir = rayEnd - rayStart;
315
316 float d = (float)Math.Sqrt(dir[0] * dir[0] + dir[1] * dir[1] + dir[2] * dir[2]);
317 float r = 1.0f / d;
318
319 dir *= r;
320
321 float t;
322 bool ret = rayIntersectsTriangle(rayStart, dir, p1, p2, p3, out t);
323
324 if (ret)
325 {
326 if (t > d)
327 {
328 sect.x = rayStart.x + dir.x * t;
329 sect.y = rayStart.y + dir.y * t;
330 sect.z = rayStart.z + dir.z * t;
331 }
332 else
333 {
334 ret = false;
335 }
336 }
337
338 return ret;
339 }
340 }
341}
diff --git a/OpenSim/Region/Physics/ConvexDecompositionDotNet/Concavity.cs b/OpenSim/Region/Physics/ConvexDecompositionDotNet/Concavity.cs
new file mode 100644
index 0000000..cc6383a
--- /dev/null
+++ b/OpenSim/Region/Physics/ConvexDecompositionDotNet/Concavity.cs
@@ -0,0 +1,233 @@
1/* The MIT License
2 *
3 * Copyright (c) 2010 Intel Corporation.
4 * All rights reserved.
5 *
6 * Based on the convexdecomposition library from
7 * <http://codesuppository.googlecode.com> by John W. Ratcliff and Stan Melax.
8 *
9 * Permission is hereby granted, free of charge, to any person obtaining a copy
10 * of this software and associated documentation files (the "Software"), to deal
11 * in the Software without restriction, including without limitation the rights
12 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
13 * copies of the Software, and to permit persons to whom the Software is
14 * furnished to do so, subject to the following conditions:
15 *
16 * The above copyright notice and this permission notice shall be included in
17 * all copies or substantial portions of the Software.
18 *
19 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
20 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
21 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
22 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
23 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
24 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
25 * THE SOFTWARE.
26 */
27
28using System;
29using System.Collections.Generic;
30using System.Text;
31
32namespace OpenSim.Region.Physics.ConvexDecompositionDotNet
33{
34 public static class Concavity
35 {
36 // compute's how 'concave' this object is and returns the total volume of the
37 // convex hull as well as the volume of the 'concavity' which was found.
38 public static float computeConcavity(List<float3> vertices, List<int> indices, ref float4 plane, ref float volume)
39 {
40 float cret = 0f;
41 volume = 1f;
42
43 HullResult result = new HullResult();
44 HullDesc desc = new HullDesc();
45
46 desc.MaxFaces = 256;
47 desc.MaxVertices = 256;
48 desc.SetHullFlag(HullFlag.QF_TRIANGLES);
49 desc.Vertices = vertices;
50
51 HullError ret = HullUtils.CreateConvexHull(desc, ref result);
52
53 if (ret == HullError.QE_OK)
54 {
55 volume = computeMeshVolume2(result.OutputVertices, result.Indices);
56
57 // ok..now..for each triangle on the original mesh..
58 // we extrude the points to the nearest point on the hull.
59 List<CTri> tris = new List<CTri>();
60
61 for (int i = 0; i < result.Indices.Count / 3; i++)
62 {
63 int i1 = result.Indices[i * 3 + 0];
64 int i2 = result.Indices[i * 3 + 1];
65 int i3 = result.Indices[i * 3 + 2];
66
67 float3 p1 = result.OutputVertices[i1];
68 float3 p2 = result.OutputVertices[i2];
69 float3 p3 = result.OutputVertices[i3];
70
71 CTri t = new CTri(p1, p2, p3, i1, i2, i3);
72 tris.Add(t);
73 }
74
75 // we have not pre-computed the plane equation for each triangle in the convex hull..
76 float totalVolume = 0;
77
78 List<CTri> ftris = new List<CTri>(); // 'feature' triangles.
79 List<CTri> input_mesh = new List<CTri>();
80
81 for (int i = 0; i < indices.Count / 3; i++)
82 {
83 int i1 = indices[i * 3 + 0];
84 int i2 = indices[i * 3 + 1];
85 int i3 = indices[i * 3 + 2];
86
87 float3 p1 = vertices[i1];
88 float3 p2 = vertices[i2];
89 float3 p3 = vertices[i3];
90
91 CTri t = new CTri(p1, p2, p3, i1, i2, i3);
92 input_mesh.Add(t);
93 }
94
95 for (int i = 0; i < indices.Count / 3; i++)
96 {
97 int i1 = indices[i * 3 + 0];
98 int i2 = indices[i * 3 + 1];
99 int i3 = indices[i * 3 + 2];
100
101 float3 p1 = vertices[i1];
102 float3 p2 = vertices[i2];
103 float3 p3 = vertices[i3];
104
105 CTri t = new CTri(p1, p2, p3, i1, i2, i3);
106
107 featureMatch(t, tris, input_mesh);
108
109 if (t.mConcavity > 0.05f)
110 {
111 float v = t.getVolume();
112 totalVolume += v;
113 ftris.Add(t);
114 }
115 }
116
117 SplitPlane.computeSplitPlane(vertices, indices, ref plane);
118 cret = totalVolume;
119 }
120
121 return cret;
122 }
123
124 public static bool featureMatch(CTri m, List<CTri> tris, List<CTri> input_mesh)
125 {
126 bool ret = false;
127 float neardot = 0.707f;
128 m.mConcavity = 0;
129
130 for (int i = 0; i < tris.Count; i++)
131 {
132 CTri t = tris[i];
133
134 if (t.samePlane(m))
135 {
136 ret = false;
137 break;
138 }
139
140 float dot = float3.dot(t.mNormal, m.mNormal);
141
142 if (dot > neardot)
143 {
144 float d1 = t.planeDistance(m.mP1);
145 float d2 = t.planeDistance(m.mP2);
146 float d3 = t.planeDistance(m.mP3);
147
148 if (d1 > 0.001f || d2 > 0.001f || d3 > 0.001f) // can't be near coplaner!
149 {
150 neardot = dot;
151
152 t.raySect(m.mP1, m.mNormal, ref m.mNear1);
153 t.raySect(m.mP2, m.mNormal, ref m.mNear2);
154 t.raySect(m.mP3, m.mNormal, ref m.mNear3);
155
156 ret = true;
157 }
158 }
159 }
160
161 if (ret)
162 {
163 m.mC1 = m.mP1.Distance(m.mNear1);
164 m.mC2 = m.mP2.Distance(m.mNear2);
165 m.mC3 = m.mP3.Distance(m.mNear3);
166
167 m.mConcavity = m.mC1;
168
169 if (m.mC2 > m.mConcavity)
170 m.mConcavity = m.mC2;
171 if (m.mC3 > m.mConcavity)
172 m.mConcavity = m.mC3;
173 }
174
175 return ret;
176 }
177
178 private static float det(float3 p1, float3 p2, float3 p3)
179 {
180 return p1.x * p2.y * p3.z + p2.x * p3.y * p1.z + p3.x * p1.y * p2.z - p1.x * p3.y * p2.z - p2.x * p1.y * p3.z - p3.x * p2.y * p1.z;
181 }
182
183 public static float computeMeshVolume(List<float3> vertices, List<int> indices)
184 {
185 float volume = 0f;
186
187 for (int i = 0; i < indices.Count / 3; i++)
188 {
189 float3 p1 = vertices[indices[i * 3 + 0]];
190 float3 p2 = vertices[indices[i * 3 + 1]];
191 float3 p3 = vertices[indices[i * 3 + 2]];
192
193 volume += det(p1, p2, p3); // compute the volume of the tetrahedran relative to the origin.
194 }
195
196 volume *= (1.0f / 6.0f);
197 if (volume < 0f)
198 return -volume;
199 return volume;
200 }
201
202 public static float computeMeshVolume2(List<float3> vertices, List<int> indices)
203 {
204 float volume = 0f;
205
206 float3 p0 = vertices[0];
207 for (int i = 0; i < indices.Count / 3; i++)
208 {
209 float3 p1 = vertices[indices[i * 3 + 0]];
210 float3 p2 = vertices[indices[i * 3 + 1]];
211 float3 p3 = vertices[indices[i * 3 + 2]];
212
213 volume += tetVolume(p0, p1, p2, p3); // compute the volume of the tetrahedron relative to the root vertice
214 }
215
216 return volume * (1.0f / 6.0f);
217 }
218
219 private static float tetVolume(float3 p0, float3 p1, float3 p2, float3 p3)
220 {
221 float3 a = p1 - p0;
222 float3 b = p2 - p0;
223 float3 c = p3 - p0;
224
225 float3 cross = float3.cross(b, c);
226 float volume = float3.dot(a, cross);
227
228 if (volume < 0f)
229 return -volume;
230 return volume;
231 }
232 }
233}
diff --git a/OpenSim/Region/Physics/ConvexDecompositionDotNet/ConvexBuilder.cs b/OpenSim/Region/Physics/ConvexDecompositionDotNet/ConvexBuilder.cs
new file mode 100644
index 0000000..dfaede1
--- /dev/null
+++ b/OpenSim/Region/Physics/ConvexDecompositionDotNet/ConvexBuilder.cs
@@ -0,0 +1,411 @@
1/* The MIT License
2 *
3 * Copyright (c) 2010 Intel Corporation.
4 * All rights reserved.
5 *
6 * Based on the convexdecomposition library from
7 * <http://codesuppository.googlecode.com> by John W. Ratcliff and Stan Melax.
8 *
9 * Permission is hereby granted, free of charge, to any person obtaining a copy
10 * of this software and associated documentation files (the "Software"), to deal
11 * in the Software without restriction, including without limitation the rights
12 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
13 * copies of the Software, and to permit persons to whom the Software is
14 * furnished to do so, subject to the following conditions:
15 *
16 * The above copyright notice and this permission notice shall be included in
17 * all copies or substantial portions of the Software.
18 *
19 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
20 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
21 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
22 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
23 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
24 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
25 * THE SOFTWARE.
26 */
27
28using System;
29using System.Collections.Generic;
30using System.Diagnostics;
31
32namespace OpenSim.Region.Physics.ConvexDecompositionDotNet
33{
34 public class DecompDesc
35 {
36 public List<float3> mVertices;
37 public List<int> mIndices;
38
39 // options
40 public uint mDepth; // depth to split, a maximum of 10, generally not over 7.
41 public float mCpercent; // the concavity threshold percentage. 0=20 is reasonable.
42 public float mPpercent; // the percentage volume conservation threshold to collapse hulls. 0-30 is reasonable.
43
44 // hull output limits.
45 public uint mMaxVertices; // maximum number of vertices in the output hull. Recommended 32 or less.
46 public float mSkinWidth; // a skin width to apply to the output hulls.
47
48 public ConvexDecompositionCallback mCallback; // the interface to receive back the results.
49
50 public DecompDesc()
51 {
52 mDepth = 5;
53 mCpercent = 5;
54 mPpercent = 5;
55 mMaxVertices = 32;
56 }
57 }
58
59 public class CHull
60 {
61 public float[] mMin = new float[3];
62 public float[] mMax = new float[3];
63 public float mVolume;
64 public float mDiagonal;
65 public ConvexResult mResult;
66
67 public CHull(ConvexResult result)
68 {
69 mResult = new ConvexResult(result);
70 mVolume = Concavity.computeMeshVolume(result.HullVertices, result.HullIndices);
71
72 mDiagonal = getBoundingRegion(result.HullVertices, mMin, mMax);
73
74 float dx = mMax[0] - mMin[0];
75 float dy = mMax[1] - mMin[1];
76 float dz = mMax[2] - mMin[2];
77
78 dx *= 0.1f; // inflate 1/10th on each edge
79 dy *= 0.1f; // inflate 1/10th on each edge
80 dz *= 0.1f; // inflate 1/10th on each edge
81
82 mMin[0] -= dx;
83 mMin[1] -= dy;
84 mMin[2] -= dz;
85
86 mMax[0] += dx;
87 mMax[1] += dy;
88 mMax[2] += dz;
89 }
90
91 public void Dispose()
92 {
93 mResult = null;
94 }
95
96 public bool overlap(CHull h)
97 {
98 return overlapAABB(mMin, mMax, h.mMin, h.mMax);
99 }
100
101 // returns the d1Giagonal distance
102 private static float getBoundingRegion(List<float3> points, float[] bmin, float[] bmax)
103 {
104 float3 first = points[0];
105
106 bmin[0] = first.x;
107 bmin[1] = first.y;
108 bmin[2] = first.z;
109
110 bmax[0] = first.x;
111 bmax[1] = first.y;
112 bmax[2] = first.z;
113
114 for (int i = 1; i < points.Count; i++)
115 {
116 float3 p = points[i];
117
118 if (p[0] < bmin[0]) bmin[0] = p[0];
119 if (p[1] < bmin[1]) bmin[1] = p[1];
120 if (p[2] < bmin[2]) bmin[2] = p[2];
121
122 if (p[0] > bmax[0]) bmax[0] = p[0];
123 if (p[1] > bmax[1]) bmax[1] = p[1];
124 if (p[2] > bmax[2]) bmax[2] = p[2];
125 }
126
127 float dx = bmax[0] - bmin[0];
128 float dy = bmax[1] - bmin[1];
129 float dz = bmax[2] - bmin[2];
130
131 return (float)Math.Sqrt(dx * dx + dy * dy + dz * dz);
132 }
133
134 // return true if the two AABB's overlap.
135 private static bool overlapAABB(float[] bmin1, float[] bmax1, float[] bmin2, float[] bmax2)
136 {
137 if (bmax2[0] < bmin1[0]) return false; // if the maximum is less than our minimum on any axis
138 if (bmax2[1] < bmin1[1]) return false;
139 if (bmax2[2] < bmin1[2]) return false;
140
141 if (bmin2[0] > bmax1[0]) return false; // if the minimum is greater than our maximum on any axis
142 if (bmin2[1] > bmax1[1]) return false; // if the minimum is greater than our maximum on any axis
143 if (bmin2[2] > bmax1[2]) return false; // if the minimum is greater than our maximum on any axis
144
145 return true; // the extents overlap
146 }
147 }
148
149 public class ConvexBuilder
150 {
151 public List<CHull> mChulls = new List<CHull>();
152 private ConvexDecompositionCallback mCallback;
153
154 private int MAXDEPTH = 8;
155 private float CONCAVE_PERCENT = 1f;
156 private float MERGE_PERCENT = 2f;
157
158 public ConvexBuilder(ConvexDecompositionCallback callback)
159 {
160 mCallback = callback;
161 }
162
163 public void Dispose()
164 {
165 int i;
166 for (i = 0; i < mChulls.Count; i++)
167 {
168 CHull cr = mChulls[i];
169 cr.Dispose();
170 }
171 }
172
173 public bool isDuplicate(uint i1, uint i2, uint i3, uint ci1, uint ci2, uint ci3)
174 {
175 uint dcount = 0;
176
177 Debug.Assert(i1 != i2 && i1 != i3 && i2 != i3);
178 Debug.Assert(ci1 != ci2 && ci1 != ci3 && ci2 != ci3);
179
180 if (i1 == ci1 || i1 == ci2 || i1 == ci3)
181 dcount++;
182 if (i2 == ci1 || i2 == ci2 || i2 == ci3)
183 dcount++;
184 if (i3 == ci1 || i3 == ci2 || i3 == ci3)
185 dcount++;
186
187 return dcount == 3;
188 }
189
190 public void getMesh(ConvexResult cr, VertexPool vc, List<int> indices)
191 {
192 List<int> src = cr.HullIndices;
193
194 for (int i = 0; i < src.Count / 3; i++)
195 {
196 int i1 = src[i * 3 + 0];
197 int i2 = src[i * 3 + 1];
198 int i3 = src[i * 3 + 2];
199
200 float3 p1 = cr.HullVertices[i1];
201 float3 p2 = cr.HullVertices[i2];
202 float3 p3 = cr.HullVertices[i3];
203
204 i1 = vc.getIndex(p1);
205 i2 = vc.getIndex(p2);
206 i3 = vc.getIndex(p3);
207 }
208 }
209
210 public CHull canMerge(CHull a, CHull b)
211 {
212 if (!a.overlap(b)) // if their AABB's (with a little slop) don't overlap, then return.
213 return null;
214
215 CHull ret = null;
216
217 // ok..we are going to combine both meshes into a single mesh
218 // and then we are going to compute the concavity...
219
220 VertexPool vc = new VertexPool();
221
222 List<int> indices = new List<int>();
223
224 getMesh(a.mResult, vc, indices);
225 getMesh(b.mResult, vc, indices);
226
227 int vcount = vc.GetSize();
228 List<float3> vertices = vc.GetVertices();
229 int tcount = indices.Count / 3;
230
231 //don't do anything if hull is empty
232 if (tcount == 0)
233 {
234 vc.Clear();
235 return null;
236 }
237
238 HullResult hresult = new HullResult();
239 HullDesc desc = new HullDesc();
240
241 desc.SetHullFlag(HullFlag.QF_TRIANGLES);
242 desc.Vertices = vertices;
243
244 HullError hret = HullUtils.CreateConvexHull(desc, ref hresult);
245
246 if (hret == HullError.QE_OK)
247 {
248 float combineVolume = Concavity.computeMeshVolume(hresult.OutputVertices, hresult.Indices);
249 float sumVolume = a.mVolume + b.mVolume;
250
251 float percent = (sumVolume * 100) / combineVolume;
252 if (percent >= (100.0f - MERGE_PERCENT))
253 {
254 ConvexResult cr = new ConvexResult(hresult.OutputVertices, hresult.Indices);
255 ret = new CHull(cr);
256 }
257 }
258
259 vc.Clear();
260 return ret;
261 }
262
263 public bool combineHulls()
264 {
265 bool combine = false;
266
267 sortChulls(mChulls); // sort the convex hulls, largest volume to least...
268
269 List<CHull> output = new List<CHull>(); // the output hulls...
270
271 int i;
272 for (i = 0; i < mChulls.Count && !combine; ++i)
273 {
274 CHull cr = mChulls[i];
275
276 int j;
277 for (j = 0; j < mChulls.Count; j++)
278 {
279 CHull match = mChulls[j];
280
281 if (cr != match) // don't try to merge a hull with itself, that be stoopid
282 {
283
284 CHull merge = canMerge(cr, match); // if we can merge these two....
285
286 if (merge != null)
287 {
288 output.Add(merge);
289
290 ++i;
291 while (i != mChulls.Count)
292 {
293 CHull cr2 = mChulls[i];
294 if (cr2 != match)
295 {
296 output.Add(cr2);
297 }
298 i++;
299 }
300
301 cr.Dispose();
302 match.Dispose();
303 combine = true;
304 break;
305 }
306 }
307 }
308
309 if (combine)
310 {
311 break;
312 }
313 else
314 {
315 output.Add(cr);
316 }
317 }
318
319 if (combine)
320 {
321 mChulls.Clear();
322 mChulls = output;
323 output.Clear();
324 }
325
326 return combine;
327 }
328
329 public int process(DecompDesc desc)
330 {
331 int ret = 0;
332
333 MAXDEPTH = (int)desc.mDepth;
334 CONCAVE_PERCENT = desc.mCpercent;
335 MERGE_PERCENT = desc.mPpercent;
336
337 ConvexDecomposition.calcConvexDecomposition(desc.mVertices, desc.mIndices, ConvexDecompResult, 0f, 0, MAXDEPTH, CONCAVE_PERCENT, MERGE_PERCENT);
338
339 while (combineHulls()) // keep combinging hulls until I can't combine any more...
340 ;
341
342 int i;
343 for (i = 0; i < mChulls.Count; i++)
344 {
345 CHull cr = mChulls[i];
346
347 // before we hand it back to the application, we need to regenerate the hull based on the
348 // limits given by the user.
349
350 ConvexResult c = cr.mResult; // the high resolution hull...
351
352 HullResult result = new HullResult();
353 HullDesc hdesc = new HullDesc();
354
355 hdesc.SetHullFlag(HullFlag.QF_TRIANGLES);
356
357 hdesc.Vertices = c.HullVertices;
358 hdesc.MaxVertices = desc.mMaxVertices; // maximum number of vertices allowed in the output
359
360 if (desc.mSkinWidth != 0f)
361 {
362 hdesc.SkinWidth = desc.mSkinWidth;
363 hdesc.SetHullFlag(HullFlag.QF_SKIN_WIDTH); // do skin width computation.
364 }
365
366 HullError ret2 = HullUtils.CreateConvexHull(hdesc, ref result);
367
368 if (ret2 == HullError.QE_OK)
369 {
370 ConvexResult r = new ConvexResult(result.OutputVertices, result.Indices);
371
372 r.mHullVolume = Concavity.computeMeshVolume(result.OutputVertices, result.Indices); // the volume of the hull.
373
374 // compute the best fit OBB
375 //computeBestFitOBB(result.mNumOutputVertices, result.mOutputVertices, sizeof(float) * 3, r.mOBBSides, r.mOBBTransform);
376
377 //r.mOBBVolume = r.mOBBSides[0] * r.mOBBSides[1] * r.mOBBSides[2]; // compute the OBB volume.
378
379 //fm_getTranslation(r.mOBBTransform, r.mOBBCenter); // get the translation component of the 4x4 matrix.
380
381 //fm_matrixToQuat(r.mOBBTransform, r.mOBBOrientation); // extract the orientation as a quaternion.
382
383 //r.mSphereRadius = computeBoundingSphere(result.mNumOutputVertices, result.mOutputVertices, r.mSphereCenter);
384 //r.mSphereVolume = fm_sphereVolume(r.mSphereRadius);
385
386 mCallback(r);
387 }
388
389 result = null;
390 cr.Dispose();
391 }
392
393 ret = mChulls.Count;
394
395 mChulls.Clear();
396
397 return ret;
398 }
399
400 public void ConvexDecompResult(ConvexResult result)
401 {
402 CHull ch = new CHull(result);
403 mChulls.Add(ch);
404 }
405
406 public void sortChulls(List<CHull> hulls)
407 {
408 hulls.Sort(delegate(CHull a, CHull b) { return a.mVolume.CompareTo(b.mVolume); });
409 }
410 }
411}
diff --git a/OpenSim/Region/Physics/ConvexDecompositionDotNet/ConvexDecomposition.cs b/OpenSim/Region/Physics/ConvexDecompositionDotNet/ConvexDecomposition.cs
new file mode 100644
index 0000000..2e2bb70
--- /dev/null
+++ b/OpenSim/Region/Physics/ConvexDecompositionDotNet/ConvexDecomposition.cs
@@ -0,0 +1,200 @@
1/* The MIT License
2 *
3 * Copyright (c) 2010 Intel Corporation.
4 * All rights reserved.
5 *
6 * Based on the convexdecomposition library from
7 * <http://codesuppository.googlecode.com> by John W. Ratcliff and Stan Melax.
8 *
9 * Permission is hereby granted, free of charge, to any person obtaining a copy
10 * of this software and associated documentation files (the "Software"), to deal
11 * in the Software without restriction, including without limitation the rights
12 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
13 * copies of the Software, and to permit persons to whom the Software is
14 * furnished to do so, subject to the following conditions:
15 *
16 * The above copyright notice and this permission notice shall be included in
17 * all copies or substantial portions of the Software.
18 *
19 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
20 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
21 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
22 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
23 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
24 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
25 * THE SOFTWARE.
26 */
27
28using System;
29using System.Collections.Generic;
30using System.Diagnostics;
31
32namespace OpenSim.Region.Physics.ConvexDecompositionDotNet
33{
34 public delegate void ConvexDecompositionCallback(ConvexResult result);
35
36 public class FaceTri
37 {
38 public float3 P1;
39 public float3 P2;
40 public float3 P3;
41
42 public FaceTri() { }
43
44 public FaceTri(List<float3> vertices, int i1, int i2, int i3)
45 {
46 P1 = new float3(vertices[i1]);
47 P2 = new float3(vertices[i2]);
48 P3 = new float3(vertices[i3]);
49 }
50 }
51
52 public static class ConvexDecomposition
53 {
54 private static void addTri(VertexPool vl, List<int> list, float3 p1, float3 p2, float3 p3)
55 {
56 int i1 = vl.getIndex(p1);
57 int i2 = vl.getIndex(p2);
58 int i3 = vl.getIndex(p3);
59
60 // do *not* process degenerate triangles!
61 if ( i1 != i2 && i1 != i3 && i2 != i3 )
62 {
63 list.Add(i1);
64 list.Add(i2);
65 list.Add(i3);
66 }
67 }
68
69 public static void calcConvexDecomposition(List<float3> vertices, List<int> indices, ConvexDecompositionCallback callback, float masterVolume, int depth,
70 int maxDepth, float concavePercent, float mergePercent)
71 {
72 float4 plane = new float4();
73 bool split = false;
74
75 if (depth < maxDepth)
76 {
77 float volume = 0f;
78 float c = Concavity.computeConcavity(vertices, indices, ref plane, ref volume);
79
80 if (depth == 0)
81 {
82 masterVolume = volume;
83 }
84
85 float percent = (c * 100.0f) / masterVolume;
86
87 if (percent > concavePercent) // if great than 5% of the total volume is concave, go ahead and keep splitting.
88 {
89 split = true;
90 }
91 }
92
93 if (depth >= maxDepth || !split)
94 {
95 HullResult result = new HullResult();
96 HullDesc desc = new HullDesc();
97
98 desc.SetHullFlag(HullFlag.QF_TRIANGLES);
99
100 desc.Vertices = vertices;
101
102 HullError ret = HullUtils.CreateConvexHull(desc, ref result);
103
104 if (ret == HullError.QE_OK)
105 {
106 ConvexResult r = new ConvexResult(result.OutputVertices, result.Indices);
107 callback(r);
108 }
109
110 return;
111 }
112
113 List<int> ifront = new List<int>();
114 List<int> iback = new List<int>();
115
116 VertexPool vfront = new VertexPool();
117 VertexPool vback = new VertexPool();
118
119 // ok..now we are going to 'split' all of the input triangles against this plane!
120 for (int i = 0; i < indices.Count / 3; i++)
121 {
122 int i1 = indices[i * 3 + 0];
123 int i2 = indices[i * 3 + 1];
124 int i3 = indices[i * 3 + 2];
125
126 FaceTri t = new FaceTri(vertices, i1, i2, i3);
127
128 float3[] front = new float3[4];
129 float3[] back = new float3[4];
130
131 int fcount = 0;
132 int bcount = 0;
133
134 PlaneTriResult result = PlaneTri.planeTriIntersection(plane, t, 0.00001f, ref front, out fcount, ref back, out bcount);
135
136 if (fcount > 4 || bcount > 4)
137 {
138 result = PlaneTri.planeTriIntersection(plane, t, 0.00001f, ref front, out fcount, ref back, out bcount);
139 }
140
141 switch (result)
142 {
143 case PlaneTriResult.PTR_FRONT:
144 Debug.Assert(fcount == 3);
145 addTri(vfront, ifront, front[0], front[1], front[2]);
146 break;
147 case PlaneTriResult.PTR_BACK:
148 Debug.Assert(bcount == 3);
149 addTri(vback, iback, back[0], back[1], back[2]);
150 break;
151 case PlaneTriResult.PTR_SPLIT:
152 Debug.Assert(fcount >= 3 && fcount <= 4);
153 Debug.Assert(bcount >= 3 && bcount <= 4);
154
155 addTri(vfront, ifront, front[0], front[1], front[2]);
156 addTri(vback, iback, back[0], back[1], back[2]);
157
158 if (fcount == 4)
159 {
160 addTri(vfront, ifront, front[0], front[2], front[3]);
161 }
162
163 if (bcount == 4)
164 {
165 addTri(vback, iback, back[0], back[2], back[3]);
166 }
167
168 break;
169 }
170 }
171
172 // ok... here we recursively call
173 if (ifront.Count > 0)
174 {
175 int vcount = vfront.GetSize();
176 List<float3> vertices2 = vfront.GetVertices();
177 for (int i = 0; i < vertices2.Count; i++)
178 vertices2[i] = new float3(vertices2[i]);
179 int tcount = ifront.Count / 3;
180
181 calcConvexDecomposition(vertices2, ifront, callback, masterVolume, depth + 1, maxDepth, concavePercent, mergePercent);
182 }
183
184 ifront.Clear();
185 vfront.Clear();
186
187 if (iback.Count > 0)
188 {
189 int vcount = vback.GetSize();
190 List<float3> vertices2 = vback.GetVertices();
191 int tcount = iback.Count / 3;
192
193 calcConvexDecomposition(vertices2, iback, callback, masterVolume, depth + 1, maxDepth, concavePercent, mergePercent);
194 }
195
196 iback.Clear();
197 vback.Clear();
198 }
199 }
200}
diff --git a/OpenSim/Region/Physics/ConvexDecompositionDotNet/ConvexResult.cs b/OpenSim/Region/Physics/ConvexDecompositionDotNet/ConvexResult.cs
new file mode 100644
index 0000000..87758b5
--- /dev/null
+++ b/OpenSim/Region/Physics/ConvexDecompositionDotNet/ConvexResult.cs
@@ -0,0 +1,74 @@
1/* The MIT License
2 *
3 * Copyright (c) 2010 Intel Corporation.
4 * All rights reserved.
5 *
6 * Based on the convexdecomposition library from
7 * <http://codesuppository.googlecode.com> by John W. Ratcliff and Stan Melax.
8 *
9 * Permission is hereby granted, free of charge, to any person obtaining a copy
10 * of this software and associated documentation files (the "Software"), to deal
11 * in the Software without restriction, including without limitation the rights
12 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
13 * copies of the Software, and to permit persons to whom the Software is
14 * furnished to do so, subject to the following conditions:
15 *
16 * The above copyright notice and this permission notice shall be included in
17 * all copies or substantial portions of the Software.
18 *
19 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
20 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
21 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
22 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
23 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
24 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
25 * THE SOFTWARE.
26 */
27
28using System;
29using System.Collections.Generic;
30
31namespace OpenSim.Region.Physics.ConvexDecompositionDotNet
32{
33 public class ConvexResult
34 {
35 public List<float3> HullVertices;
36 public List<int> HullIndices;
37
38 public float mHullVolume; // the volume of the convex hull.
39
40 //public float[] OBBSides = new float[3]; // the width, height and breadth of the best fit OBB
41 //public float[] OBBCenter = new float[3]; // the center of the OBB
42 //public float[] OBBOrientation = new float[4]; // the quaternion rotation of the OBB.
43 //public float[] OBBTransform = new float[16]; // the 4x4 transform of the OBB.
44 //public float OBBVolume; // the volume of the OBB
45
46 //public float SphereRadius; // radius and center of best fit sphere
47 //public float[] SphereCenter = new float[3];
48 //public float SphereVolume; // volume of the best fit sphere
49
50 public ConvexResult()
51 {
52 HullVertices = new List<float3>();
53 HullIndices = new List<int>();
54 }
55
56 public ConvexResult(List<float3> hvertices, List<int> hindices)
57 {
58 HullVertices = hvertices;
59 HullIndices = hindices;
60 }
61
62 public ConvexResult(ConvexResult r)
63 {
64 HullVertices = new List<float3>(r.HullVertices);
65 HullIndices = new List<int>(r.HullIndices);
66 }
67
68 public void Dispose()
69 {
70 HullVertices = null;
71 HullIndices = null;
72 }
73 }
74}
diff --git a/OpenSim/Region/Physics/ConvexDecompositionDotNet/HullClasses.cs b/OpenSim/Region/Physics/ConvexDecompositionDotNet/HullClasses.cs
new file mode 100644
index 0000000..d81df26
--- /dev/null
+++ b/OpenSim/Region/Physics/ConvexDecompositionDotNet/HullClasses.cs
@@ -0,0 +1,171 @@
1/* The MIT License
2 *
3 * Copyright (c) 2010 Intel Corporation.
4 * All rights reserved.
5 *
6 * Based on the convexdecomposition library from
7 * <http://codesuppository.googlecode.com> by John W. Ratcliff and Stan Melax.
8 *
9 * Permission is hereby granted, free of charge, to any person obtaining a copy
10 * of this software and associated documentation files (the "Software"), to deal
11 * in the Software without restriction, including without limitation the rights
12 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
13 * copies of the Software, and to permit persons to whom the Software is
14 * furnished to do so, subject to the following conditions:
15 *
16 * The above copyright notice and this permission notice shall be included in
17 * all copies or substantial portions of the Software.
18 *
19 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
20 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
21 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
22 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
23 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
24 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
25 * THE SOFTWARE.
26 */
27
28using System;
29using System.Collections.Generic;
30
31namespace OpenSim.Region.Physics.ConvexDecompositionDotNet
32{
33 public class HullResult
34 {
35 public bool Polygons = true; // true if indices represents polygons, false indices are triangles
36 public List<float3> OutputVertices = new List<float3>();
37 public List<int> Indices;
38
39 // If triangles, then indices are array indexes into the vertex list.
40 // If polygons, indices are in the form (number of points in face) (p1, p2, p3, ..) etc..
41 }
42
43 public class PHullResult
44 {
45 public List<float3> Vertices = new List<float3>();
46 public List<int> Indices = new List<int>();
47 }
48
49 [Flags]
50 public enum HullFlag : int
51 {
52 QF_DEFAULT = 0,
53 QF_TRIANGLES = (1 << 0), // report results as triangles, not polygons.
54 QF_SKIN_WIDTH = (1 << 2) // extrude hull based on this skin width
55 }
56
57 public enum HullError : int
58 {
59 QE_OK, // success!
60 QE_FAIL // failed.
61 }
62
63 public class HullDesc
64 {
65 public HullFlag Flags; // flags to use when generating the convex hull.
66 public List<float3> Vertices;
67 public float NormalEpsilon; // the epsilon for removing duplicates. This is a normalized value, if normalized bit is on.
68 public float SkinWidth;
69 public uint MaxVertices; // maximum number of vertices to be considered for the hull!
70 public uint MaxFaces;
71
72 public HullDesc()
73 {
74 Flags = HullFlag.QF_DEFAULT;
75 Vertices = new List<float3>();
76 NormalEpsilon = 0.001f;
77 MaxVertices = 4096;
78 MaxFaces = 4096;
79 SkinWidth = 0.01f;
80 }
81
82 public HullDesc(HullFlag flags, List<float3> vertices)
83 {
84 Flags = flags;
85 Vertices = new List<float3>(vertices);
86 NormalEpsilon = 0.001f;
87 MaxVertices = 4096;
88 MaxFaces = 4096;
89 SkinWidth = 0.01f;
90 }
91
92 public bool HasHullFlag(HullFlag flag)
93 {
94 return (Flags & flag) != 0;
95 }
96
97 public void SetHullFlag(HullFlag flag)
98 {
99 Flags |= flag;
100 }
101
102 public void ClearHullFlag(HullFlag flag)
103 {
104 Flags &= ~flag;
105 }
106 }
107
108 public class ConvexH
109 {
110 public struct HalfEdge
111 {
112 public short ea; // the other half of the edge (index into edges list)
113 public byte v; // the vertex at the start of this edge (index into vertices list)
114 public byte p; // the facet on which this edge lies (index into facets list)
115
116 public HalfEdge(short _ea, byte _v, byte _p)
117 {
118 ea = _ea;
119 v = _v;
120 p = _p;
121 }
122
123 public HalfEdge(HalfEdge e)
124 {
125 ea = e.ea;
126 v = e.v;
127 p = e.p;
128 }
129 }
130
131 public List<float3> vertices = new List<float3>();
132 public List<HalfEdge> edges = new List<HalfEdge>();
133 public List<Plane> facets = new List<Plane>();
134
135 public ConvexH(int vertices_size, int edges_size, int facets_size)
136 {
137 vertices = new List<float3>(vertices_size);
138 edges = new List<HalfEdge>(edges_size);
139 facets = new List<Plane>(facets_size);
140 }
141 }
142
143 public class VertFlag
144 {
145 public byte planetest;
146 public byte junk;
147 public byte undermap;
148 public byte overmap;
149 }
150
151 public class EdgeFlag
152 {
153 public byte planetest;
154 public byte fixes;
155 public short undermap;
156 public short overmap;
157 }
158
159 public class PlaneFlag
160 {
161 public byte undermap;
162 public byte overmap;
163 }
164
165 public class Coplanar
166 {
167 public ushort ea;
168 public byte v0;
169 public byte v1;
170 }
171}
diff --git a/OpenSim/Region/Physics/ConvexDecompositionDotNet/HullTriangle.cs b/OpenSim/Region/Physics/ConvexDecompositionDotNet/HullTriangle.cs
new file mode 100644
index 0000000..1119a75
--- /dev/null
+++ b/OpenSim/Region/Physics/ConvexDecompositionDotNet/HullTriangle.cs
@@ -0,0 +1,99 @@
1/* The MIT License
2 *
3 * Copyright (c) 2010 Intel Corporation.
4 * All rights reserved.
5 *
6 * Based on the convexdecomposition library from
7 * <http://codesuppository.googlecode.com> by John W. Ratcliff and Stan Melax.
8 *
9 * Permission is hereby granted, free of charge, to any person obtaining a copy
10 * of this software and associated documentation files (the "Software"), to deal
11 * in the Software without restriction, including without limitation the rights
12 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
13 * copies of the Software, and to permit persons to whom the Software is
14 * furnished to do so, subject to the following conditions:
15 *
16 * The above copyright notice and this permission notice shall be included in
17 * all copies or substantial portions of the Software.
18 *
19 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
20 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
21 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
22 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
23 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
24 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
25 * THE SOFTWARE.
26 */
27
28using System;
29using System.Collections.Generic;
30using System.Diagnostics;
31
32namespace OpenSim.Region.Physics.ConvexDecompositionDotNet
33{
34 public class HullTriangle : int3
35 {
36 public int3 n = new int3();
37 public int id;
38 public int vmax;
39 public float rise;
40 private List<HullTriangle> tris;
41
42 public HullTriangle(int a, int b, int c, List<HullTriangle> tris)
43 : base(a, b, c)
44 {
45 this.tris = tris;
46
47 n = new int3(-1, -1, -1);
48 id = tris.Count;
49 tris.Add(this);
50 vmax = -1;
51 rise = 0.0f;
52 }
53
54 public void Dispose()
55 {
56 Debug.Assert(tris[id] == this);
57 tris[id] = null;
58 }
59
60 public int neib(int a, int b)
61 {
62 int i;
63
64 for (i = 0; i < 3; i++)
65 {
66 int i1 = (i + 1) % 3;
67 int i2 = (i + 2) % 3;
68 if ((this)[i] == a && (this)[i1] == b)
69 return n[i2];
70 if ((this)[i] == b && (this)[i1] == a)
71 return n[i2];
72 }
73
74 Debug.Assert(false);
75 return -1;
76 }
77
78 public void setneib(int a, int b, int value)
79 {
80 int i;
81
82 for (i = 0; i < 3; i++)
83 {
84 int i1 = (i + 1) % 3;
85 int i2 = (i + 2) % 3;
86 if ((this)[i] == a && (this)[i1] == b)
87 {
88 n[i2] = value;
89 return;
90 }
91 if ((this)[i] == b && (this)[i1] == a)
92 {
93 n[i2] = value;
94 return;
95 }
96 }
97 }
98 }
99}
diff --git a/OpenSim/Region/Physics/ConvexDecompositionDotNet/HullUtils.cs b/OpenSim/Region/Physics/ConvexDecompositionDotNet/HullUtils.cs
new file mode 100644
index 0000000..c9ccfe2
--- /dev/null
+++ b/OpenSim/Region/Physics/ConvexDecompositionDotNet/HullUtils.cs
@@ -0,0 +1,1868 @@
1/* The MIT License
2 *
3 * Copyright (c) 2010 Intel Corporation.
4 * All rights reserved.
5 *
6 * Based on the convexdecomposition library from
7 * <http://codesuppository.googlecode.com> by John W. Ratcliff and Stan Melax.
8 *
9 * Permission is hereby granted, free of charge, to any person obtaining a copy
10 * of this software and associated documentation files (the "Software"), to deal
11 * in the Software without restriction, including without limitation the rights
12 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
13 * copies of the Software, and to permit persons to whom the Software is
14 * furnished to do so, subject to the following conditions:
15 *
16 * The above copyright notice and this permission notice shall be included in
17 * all copies or substantial portions of the Software.
18 *
19 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
20 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
21 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
22 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
23 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
24 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
25 * THE SOFTWARE.
26 */
27
28using System;
29using System.Collections.Generic;
30using System.Diagnostics;
31
32namespace OpenSim.Region.Physics.ConvexDecompositionDotNet
33{
34 public static class HullUtils
35 {
36 public static int argmin(float[] a, int n)
37 {
38 int r = 0;
39 for (int i = 1; i < n; i++)
40 {
41 if (a[i] < a[r])
42 {
43 r = i;
44 }
45 }
46 return r;
47 }
48
49 public static float clampf(float a)
50 {
51 return Math.Min(1.0f, Math.Max(0.0f, a));
52 }
53
54 public static float Round(float a, float precision)
55 {
56 return (float)Math.Floor(0.5f + a / precision) * precision;
57 }
58
59 public static float Interpolate(float f0, float f1, float alpha)
60 {
61 return f0 * (1 - alpha) + f1 * alpha;
62 }
63
64 public static void Swap<T>(ref T a, ref T b)
65 {
66 T tmp = a;
67 a = b;
68 b = tmp;
69 }
70
71 public static bool above(List<float3> vertices, int3 t, float3 p, float epsilon)
72 {
73 float3 vtx = vertices[t.x];
74 float3 n = TriNormal(vtx, vertices[t.y], vertices[t.z]);
75 return (float3.dot(n, p - vtx) > epsilon); // EPSILON???
76 }
77
78 public static int hasedge(int3 t, int a, int b)
79 {
80 for (int i = 0; i < 3; i++)
81 {
82 int i1 = (i + 1) % 3;
83 if (t[i] == a && t[i1] == b)
84 return 1;
85 }
86 return 0;
87 }
88
89 public static bool hasvert(int3 t, int v)
90 {
91 return (t[0] == v || t[1] == v || t[2] == v);
92 }
93
94 public static int shareedge(int3 a, int3 b)
95 {
96 int i;
97 for (i = 0; i < 3; i++)
98 {
99 int i1 = (i + 1) % 3;
100 if (hasedge(a, b[i1], b[i]) != 0)
101 return 1;
102 }
103 return 0;
104 }
105
106 public static void b2bfix(HullTriangle s, HullTriangle t, List<HullTriangle> tris)
107 {
108 int i;
109 for (i = 0; i < 3; i++)
110 {
111 int i1 = (i + 1) % 3;
112 int i2 = (i + 2) % 3;
113 int a = (s)[i1];
114 int b = (s)[i2];
115 Debug.Assert(tris[s.neib(a, b)].neib(b, a) == s.id);
116 Debug.Assert(tris[t.neib(a, b)].neib(b, a) == t.id);
117 tris[s.neib(a, b)].setneib(b, a, t.neib(b, a));
118 tris[t.neib(b, a)].setneib(a, b, s.neib(a, b));
119 }
120 }
121
122 public static void removeb2b(HullTriangle s, HullTriangle t, List<HullTriangle> tris)
123 {
124 b2bfix(s, t, tris);
125 s.Dispose();
126 t.Dispose();
127 }
128
129 public static void checkit(HullTriangle t, List<HullTriangle> tris)
130 {
131 int i;
132 Debug.Assert(tris[t.id] == t);
133 for (i = 0; i < 3; i++)
134 {
135 int i1 = (i + 1) % 3;
136 int i2 = (i + 2) % 3;
137 int a = (t)[i1];
138 int b = (t)[i2];
139 Debug.Assert(a != b);
140 Debug.Assert(tris[t.n[i]].neib(b, a) == t.id);
141 }
142 }
143
144 public static void extrude(HullTriangle t0, int v, List<HullTriangle> tris)
145 {
146 int3 t = t0;
147 int n = tris.Count;
148 HullTriangle ta = new HullTriangle(v, t[1], t[2], tris);
149 ta.n = new int3(t0.n[0], n + 1, n + 2);
150 tris[t0.n[0]].setneib(t[1], t[2], n + 0);
151 HullTriangle tb = new HullTriangle(v, t[2], t[0], tris);
152 tb.n = new int3(t0.n[1], n + 2, n + 0);
153 tris[t0.n[1]].setneib(t[2], t[0], n + 1);
154 HullTriangle tc = new HullTriangle(v, t[0], t[1], tris);
155 tc.n = new int3(t0.n[2], n + 0, n + 1);
156 tris[t0.n[2]].setneib(t[0], t[1], n + 2);
157 checkit(ta, tris);
158 checkit(tb, tris);
159 checkit(tc, tris);
160 if (hasvert(tris[ta.n[0]], v))
161 removeb2b(ta, tris[ta.n[0]], tris);
162 if (hasvert(tris[tb.n[0]], v))
163 removeb2b(tb, tris[tb.n[0]], tris);
164 if (hasvert(tris[tc.n[0]], v))
165 removeb2b(tc, tris[tc.n[0]], tris);
166 t0.Dispose();
167 }
168
169 public static HullTriangle extrudable(float epsilon, List<HullTriangle> tris)
170 {
171 int i;
172 HullTriangle t = null;
173 for (i = 0; i < tris.Count; i++)
174 {
175 if (t == null || (tris.Count > i && (object)tris[i] != null && t.rise < tris[i].rise))
176 {
177 t = tris[i];
178 }
179 }
180 return (t.rise > epsilon) ? t : null;
181 }
182
183 public static Quaternion RotationArc(float3 v0, float3 v1)
184 {
185 Quaternion q = new Quaternion();
186 v0 = float3.normalize(v0); // Comment these two lines out if you know its not needed.
187 v1 = float3.normalize(v1); // If vector is already unit length then why do it again?
188 float3 c = float3.cross(v0, v1);
189 float d = float3.dot(v0, v1);
190 if (d <= -1.0f) // 180 about x axis
191 {
192 return new Quaternion(1f, 0f, 0f, 0f);
193 }
194 float s = (float)Math.Sqrt((1 + d) * 2f);
195 q.x = c.x / s;
196 q.y = c.y / s;
197 q.z = c.z / s;
198 q.w = s / 2.0f;
199 return q;
200 }
201
202 public static float3 PlaneLineIntersection(Plane plane, float3 p0, float3 p1)
203 {
204 // returns the point where the line p0-p1 intersects the plane n&d
205 float3 dif = p1 - p0;
206 float dn = float3.dot(plane.normal, dif);
207 float t = -(plane.dist + float3.dot(plane.normal, p0)) / dn;
208 return p0 + (dif * t);
209 }
210
211 public static float3 LineProject(float3 p0, float3 p1, float3 a)
212 {
213 float3 w = new float3();
214 w = p1 - p0;
215 float t = float3.dot(w, (a - p0)) / (w.x * w.x + w.y * w.y + w.z * w.z);
216 return p0 + w * t;
217 }
218
219 public static float3 PlaneProject(Plane plane, float3 point)
220 {
221 return point - plane.normal * (float3.dot(point, plane.normal) + plane.dist);
222 }
223
224 public static float LineProjectTime(float3 p0, float3 p1, float3 a)
225 {
226 float3 w = new float3();
227 w = p1 - p0;
228 float t = float3.dot(w, (a - p0)) / (w.x * w.x + w.y * w.y + w.z * w.z);
229 return t;
230 }
231
232 public static float3 ThreePlaneIntersection(Plane p0, Plane p1, Plane p2)
233 {
234 float3x3 mp = float3x3.Transpose(new float3x3(p0.normal, p1.normal, p2.normal));
235 float3x3 mi = float3x3.Inverse(mp);
236 float3 b = new float3(p0.dist, p1.dist, p2.dist);
237 return -b * mi;
238 }
239
240 public static bool PolyHit(List<float3> vert, float3 v0, float3 v1)
241 {
242 float3 impact = new float3();
243 float3 normal = new float3();
244 return PolyHit(vert, v0, v1, out impact, out normal);
245 }
246
247 public static bool PolyHit(List<float3> vert, float3 v0, float3 v1, out float3 impact)
248 {
249 float3 normal = new float3();
250 return PolyHit(vert, v0, v1, out impact, out normal);
251 }
252
253 public static bool PolyHit(List<float3> vert, float3 v0, float3 v1, out float3 impact, out float3 normal)
254 {
255 float3 the_point = new float3();
256
257 impact = null;
258 normal = null;
259
260 int i;
261 float3 nrml = new float3(0, 0, 0);
262 for (i = 0; i < vert.Count; i++)
263 {
264 int i1 = (i + 1) % vert.Count;
265 int i2 = (i + 2) % vert.Count;
266 nrml = nrml + float3.cross(vert[i1] - vert[i], vert[i2] - vert[i1]);
267 }
268
269 float m = float3.magnitude(nrml);
270 if (m == 0.0)
271 {
272 return false;
273 }
274 nrml = nrml * (1.0f / m);
275 float dist = -float3.dot(nrml, vert[0]);
276 float d0;
277 float d1;
278 if ((d0 = float3.dot(v0, nrml) + dist) < 0 || (d1 = float3.dot(v1, nrml) + dist) > 0)
279 {
280 return false;
281 }
282
283 // By using the cached plane distances d0 and d1
284 // we can optimize the following:
285 // the_point = planelineintersection(nrml,dist,v0,v1);
286 float a = d0 / (d0 - d1);
287 the_point = v0 * (1 - a) + v1 * a;
288
289
290 bool inside = true;
291 for (int j = 0; inside && j < vert.Count; j++)
292 {
293 // let inside = 0 if outside
294 float3 pp1 = new float3();
295 float3 pp2 = new float3();
296 float3 side = new float3();
297 pp1 = vert[j];
298 pp2 = vert[(j + 1) % vert.Count];
299 side = float3.cross((pp2 - pp1), (the_point - pp1));
300 inside = (float3.dot(nrml, side) >= 0.0);
301 }
302 if (inside)
303 {
304 if (normal != null)
305 {
306 normal = nrml;
307 }
308 if (impact != null)
309 {
310 impact = the_point;
311 }
312 }
313 return inside;
314 }
315
316 public static bool BoxInside(float3 p, float3 bmin, float3 bmax)
317 {
318 return (p.x >= bmin.x && p.x <= bmax.x && p.y >= bmin.y && p.y <= bmax.y && p.z >= bmin.z && p.z <= bmax.z);
319 }
320
321 public static bool BoxIntersect(float3 v0, float3 v1, float3 bmin, float3 bmax, float3 impact)
322 {
323 if (BoxInside(v0, bmin, bmax))
324 {
325 impact = v0;
326 return true;
327 }
328 if (v0.x <= bmin.x && v1.x >= bmin.x)
329 {
330 float a = (bmin.x - v0.x) / (v1.x - v0.x);
331 //v.x = bmin.x;
332 float vy = (1 - a) * v0.y + a * v1.y;
333 float vz = (1 - a) * v0.z + a * v1.z;
334 if (vy >= bmin.y && vy <= bmax.y && vz >= bmin.z && vz <= bmax.z)
335 {
336 impact.x = bmin.x;
337 impact.y = vy;
338 impact.z = vz;
339 return true;
340 }
341 }
342 else if (v0.x >= bmax.x && v1.x <= bmax.x)
343 {
344 float a = (bmax.x - v0.x) / (v1.x - v0.x);
345 //v.x = bmax.x;
346 float vy = (1 - a) * v0.y + a * v1.y;
347 float vz = (1 - a) * v0.z + a * v1.z;
348 if (vy >= bmin.y && vy <= bmax.y && vz >= bmin.z && vz <= bmax.z)
349 {
350 impact.x = bmax.x;
351 impact.y = vy;
352 impact.z = vz;
353 return true;
354 }
355 }
356 if (v0.y <= bmin.y && v1.y >= bmin.y)
357 {
358 float a = (bmin.y - v0.y) / (v1.y - v0.y);
359 float vx = (1 - a) * v0.x + a * v1.x;
360 //v.y = bmin.y;
361 float vz = (1 - a) * v0.z + a * v1.z;
362 if (vx >= bmin.x && vx <= bmax.x && vz >= bmin.z && vz <= bmax.z)
363 {
364 impact.x = vx;
365 impact.y = bmin.y;
366 impact.z = vz;
367 return true;
368 }
369 }
370 else if (v0.y >= bmax.y && v1.y <= bmax.y)
371 {
372 float a = (bmax.y - v0.y) / (v1.y - v0.y);
373 float vx = (1 - a) * v0.x + a * v1.x;
374 // vy = bmax.y;
375 float vz = (1 - a) * v0.z + a * v1.z;
376 if (vx >= bmin.x && vx <= bmax.x && vz >= bmin.z && vz <= bmax.z)
377 {
378 impact.x = vx;
379 impact.y = bmax.y;
380 impact.z = vz;
381 return true;
382 }
383 }
384 if (v0.z <= bmin.z && v1.z >= bmin.z)
385 {
386 float a = (bmin.z - v0.z) / (v1.z - v0.z);
387 float vx = (1 - a) * v0.x + a * v1.x;
388 float vy = (1 - a) * v0.y + a * v1.y;
389 // v.z = bmin.z;
390 if (vy >= bmin.y && vy <= bmax.y && vx >= bmin.x && vx <= bmax.x)
391 {
392 impact.x = vx;
393 impact.y = vy;
394 impact.z = bmin.z;
395 return true;
396 }
397 }
398 else if (v0.z >= bmax.z && v1.z <= bmax.z)
399 {
400 float a = (bmax.z - v0.z) / (v1.z - v0.z);
401 float vx = (1 - a) * v0.x + a * v1.x;
402 float vy = (1 - a) * v0.y + a * v1.y;
403 // v.z = bmax.z;
404 if (vy >= bmin.y && vy <= bmax.y && vx >= bmin.x && vx <= bmax.x)
405 {
406 impact.x = vx;
407 impact.y = vy;
408 impact.z = bmax.z;
409 return true;
410 }
411 }
412 return false;
413 }
414
415 public static float DistanceBetweenLines(float3 ustart, float3 udir, float3 vstart, float3 vdir, float3 upoint)
416 {
417 return DistanceBetweenLines(ustart, udir, vstart, vdir, upoint, null);
418 }
419
420 public static float DistanceBetweenLines(float3 ustart, float3 udir, float3 vstart, float3 vdir)
421 {
422 return DistanceBetweenLines(ustart, udir, vstart, vdir, null, null);
423 }
424
425 public static float DistanceBetweenLines(float3 ustart, float3 udir, float3 vstart, float3 vdir, float3 upoint, float3 vpoint)
426 {
427 float3 cp = float3.normalize(float3.cross(udir, vdir));
428
429 float distu = -float3.dot(cp, ustart);
430 float distv = -float3.dot(cp, vstart);
431 float dist = (float)Math.Abs(distu - distv);
432 if (upoint != null)
433 {
434 Plane plane = new Plane();
435 plane.normal = float3.normalize(float3.cross(vdir, cp));
436 plane.dist = -float3.dot(plane.normal, vstart);
437 upoint = PlaneLineIntersection(plane, ustart, ustart + udir);
438 }
439 if (vpoint != null)
440 {
441 Plane plane = new Plane();
442 plane.normal = float3.normalize(float3.cross(udir, cp));
443 plane.dist = -float3.dot(plane.normal, ustart);
444 vpoint = PlaneLineIntersection(plane, vstart, vstart + vdir);
445 }
446 return dist;
447 }
448
449 public static float3 TriNormal(float3 v0, float3 v1, float3 v2)
450 {
451 // return the normal of the triangle
452 // inscribed by v0, v1, and v2
453 float3 cp = float3.cross(v1 - v0, v2 - v1);
454 float m = float3.magnitude(cp);
455 if (m == 0)
456 return new float3(1, 0, 0);
457 return cp * (1.0f / m);
458 }
459
460 public static int PlaneTest(Plane p, float3 v, float planetestepsilon)
461 {
462 float a = float3.dot(v, p.normal) + p.dist;
463 int flag = (a > planetestepsilon) ? (2) : ((a < -planetestepsilon) ? (1) : (0));
464 return flag;
465 }
466
467 public static int SplitTest(ref ConvexH convex, Plane plane, float planetestepsilon)
468 {
469 int flag = 0;
470 for (int i = 0; i < convex.vertices.Count; i++)
471 {
472 flag |= PlaneTest(plane, convex.vertices[i], planetestepsilon);
473 }
474 return flag;
475 }
476
477 public static Quaternion VirtualTrackBall(float3 cop, float3 cor, float3 dir1, float3 dir2)
478 {
479 // routine taken from game programming gems.
480 // Implement track ball functionality to spin stuf on the screen
481 // cop center of projection
482 // cor center of rotation
483 // dir1 old mouse direction
484 // dir2 new mouse direction
485 // pretend there is a sphere around cor. Then find the points
486 // where dir1 and dir2 intersect that sphere. Find the
487 // rotation that takes the first point to the second.
488 float m;
489 // compute plane
490 float3 nrml = cor - cop;
491 float fudgefactor = 1.0f / (float3.magnitude(nrml) * 0.25f); // since trackball proportional to distance from cop
492 nrml = float3.normalize(nrml);
493 float dist = -float3.dot(nrml, cor);
494 float3 u = PlaneLineIntersection(new Plane(nrml, dist), cop, cop + dir1);
495 u = u - cor;
496 u = u * fudgefactor;
497 m = float3.magnitude(u);
498 if (m > 1)
499 {
500 u /= m;
501 }
502 else
503 {
504 u = u - (nrml * (float)Math.Sqrt(1 - m * m));
505 }
506 float3 v = PlaneLineIntersection(new Plane(nrml, dist), cop, cop + dir2);
507 v = v - cor;
508 v = v * fudgefactor;
509 m = float3.magnitude(v);
510 if (m > 1)
511 {
512 v /= m;
513 }
514 else
515 {
516 v = v - (nrml * (float)Math.Sqrt(1 - m * m));
517 }
518 return RotationArc(u, v);
519 }
520
521 public static bool AssertIntact(ConvexH convex, float planetestepsilon)
522 {
523 int i;
524 int estart = 0;
525 for (i = 0; i < convex.edges.Count; i++)
526 {
527 if (convex.edges[estart].p != convex.edges[i].p)
528 {
529 estart = i;
530 }
531 int inext = i + 1;
532 if (inext >= convex.edges.Count || convex.edges[inext].p != convex.edges[i].p)
533 {
534 inext = estart;
535 }
536 Debug.Assert(convex.edges[inext].p == convex.edges[i].p);
537 int nb = convex.edges[i].ea;
538 Debug.Assert(nb != 255);
539 if (nb == 255 || nb == -1)
540 return false;
541 Debug.Assert(nb != -1);
542 Debug.Assert(i == convex.edges[nb].ea);
543 }
544 for (i = 0; i < convex.edges.Count; i++)
545 {
546 Debug.Assert((0) == PlaneTest(convex.facets[convex.edges[i].p], convex.vertices[convex.edges[i].v], planetestepsilon));
547 if ((0) != PlaneTest(convex.facets[convex.edges[i].p], convex.vertices[convex.edges[i].v], planetestepsilon))
548 return false;
549 if (convex.edges[estart].p != convex.edges[i].p)
550 {
551 estart = i;
552 }
553 int i1 = i + 1;
554 if (i1 >= convex.edges.Count || convex.edges[i1].p != convex.edges[i].p)
555 {
556 i1 = estart;
557 }
558 int i2 = i1 + 1;
559 if (i2 >= convex.edges.Count || convex.edges[i2].p != convex.edges[i].p)
560 {
561 i2 = estart;
562 }
563 if (i == i2) // i sliced tangent to an edge and created 2 meaningless edges
564 continue;
565 float3 localnormal = TriNormal(convex.vertices[convex.edges[i].v], convex.vertices[convex.edges[i1].v], convex.vertices[convex.edges[i2].v]);
566 Debug.Assert(float3.dot(localnormal, convex.facets[convex.edges[i].p].normal) > 0);
567 if (float3.dot(localnormal, convex.facets[convex.edges[i].p].normal) <= 0)
568 return false;
569 }
570 return true;
571 }
572
573 public static ConvexH test_btbq(float planetestepsilon)
574 {
575 // back to back quads
576 ConvexH convex = new ConvexH(4, 8, 2);
577 convex.vertices[0] = new float3(0, 0, 0);
578 convex.vertices[1] = new float3(1, 0, 0);
579 convex.vertices[2] = new float3(1, 1, 0);
580 convex.vertices[3] = new float3(0, 1, 0);
581 convex.facets[0] = new Plane(new float3(0, 0, 1), 0);
582 convex.facets[1] = new Plane(new float3(0, 0, -1), 0);
583 convex.edges[0] = new ConvexH.HalfEdge(7, 0, 0);
584 convex.edges[1] = new ConvexH.HalfEdge(6, 1, 0);
585 convex.edges[2] = new ConvexH.HalfEdge(5, 2, 0);
586 convex.edges[3] = new ConvexH.HalfEdge(4, 3, 0);
587
588 convex.edges[4] = new ConvexH.HalfEdge(3, 0, 1);
589 convex.edges[5] = new ConvexH.HalfEdge(2, 3, 1);
590 convex.edges[6] = new ConvexH.HalfEdge(1, 2, 1);
591 convex.edges[7] = new ConvexH.HalfEdge(0, 1, 1);
592 AssertIntact(convex, planetestepsilon);
593 return convex;
594 }
595
596 public static ConvexH test_cube()
597 {
598 ConvexH convex = new ConvexH(8, 24, 6);
599 convex.vertices[0] = new float3(0, 0, 0);
600 convex.vertices[1] = new float3(0, 0, 1);
601 convex.vertices[2] = new float3(0, 1, 0);
602 convex.vertices[3] = new float3(0, 1, 1);
603 convex.vertices[4] = new float3(1, 0, 0);
604 convex.vertices[5] = new float3(1, 0, 1);
605 convex.vertices[6] = new float3(1, 1, 0);
606 convex.vertices[7] = new float3(1, 1, 1);
607
608 convex.facets[0] = new Plane(new float3(-1, 0, 0), 0);
609 convex.facets[1] = new Plane(new float3(1, 0, 0), -1);
610 convex.facets[2] = new Plane(new float3(0, -1, 0), 0);
611 convex.facets[3] = new Plane(new float3(0, 1, 0), -1);
612 convex.facets[4] = new Plane(new float3(0, 0, -1), 0);
613 convex.facets[5] = new Plane(new float3(0, 0, 1), -1);
614
615 convex.edges[0] = new ConvexH.HalfEdge(11, 0, 0);
616 convex.edges[1] = new ConvexH.HalfEdge(23, 1, 0);
617 convex.edges[2] = new ConvexH.HalfEdge(15, 3, 0);
618 convex.edges[3] = new ConvexH.HalfEdge(16, 2, 0);
619
620 convex.edges[4] = new ConvexH.HalfEdge(13, 6, 1);
621 convex.edges[5] = new ConvexH.HalfEdge(21, 7, 1);
622 convex.edges[6] = new ConvexH.HalfEdge(9, 5, 1);
623 convex.edges[7] = new ConvexH.HalfEdge(18, 4, 1);
624
625 convex.edges[8] = new ConvexH.HalfEdge(19, 0, 2);
626 convex.edges[9] = new ConvexH.HalfEdge(6, 4, 2);
627 convex.edges[10] = new ConvexH.HalfEdge(20, 5, 2);
628 convex.edges[11] = new ConvexH.HalfEdge(0, 1, 2);
629
630 convex.edges[12] = new ConvexH.HalfEdge(22, 3, 3);
631 convex.edges[13] = new ConvexH.HalfEdge(4, 7, 3);
632 convex.edges[14] = new ConvexH.HalfEdge(17, 6, 3);
633 convex.edges[15] = new ConvexH.HalfEdge(2, 2, 3);
634
635 convex.edges[16] = new ConvexH.HalfEdge(3, 0, 4);
636 convex.edges[17] = new ConvexH.HalfEdge(14, 2, 4);
637 convex.edges[18] = new ConvexH.HalfEdge(7, 6, 4);
638 convex.edges[19] = new ConvexH.HalfEdge(8, 4, 4);
639
640 convex.edges[20] = new ConvexH.HalfEdge(10, 1, 5);
641 convex.edges[21] = new ConvexH.HalfEdge(5, 5, 5);
642 convex.edges[22] = new ConvexH.HalfEdge(12, 7, 5);
643 convex.edges[23] = new ConvexH.HalfEdge(1, 3, 5);
644
645 return convex;
646 }
647
648 public static ConvexH ConvexHMakeCube(float3 bmin, float3 bmax)
649 {
650 ConvexH convex = test_cube();
651 convex.vertices[0] = new float3(bmin.x, bmin.y, bmin.z);
652 convex.vertices[1] = new float3(bmin.x, bmin.y, bmax.z);
653 convex.vertices[2] = new float3(bmin.x, bmax.y, bmin.z);
654 convex.vertices[3] = new float3(bmin.x, bmax.y, bmax.z);
655 convex.vertices[4] = new float3(bmax.x, bmin.y, bmin.z);
656 convex.vertices[5] = new float3(bmax.x, bmin.y, bmax.z);
657 convex.vertices[6] = new float3(bmax.x, bmax.y, bmin.z);
658 convex.vertices[7] = new float3(bmax.x, bmax.y, bmax.z);
659
660 convex.facets[0] = new Plane(new float3(-1, 0, 0), bmin.x);
661 convex.facets[1] = new Plane(new float3(1, 0, 0), -bmax.x);
662 convex.facets[2] = new Plane(new float3(0, -1, 0), bmin.y);
663 convex.facets[3] = new Plane(new float3(0, 1, 0), -bmax.y);
664 convex.facets[4] = new Plane(new float3(0, 0, -1), bmin.z);
665 convex.facets[5] = new Plane(new float3(0, 0, 1), -bmax.z);
666 return convex;
667 }
668
669 public static ConvexH ConvexHCrop(ref ConvexH convex, Plane slice, float planetestepsilon)
670 {
671 int i;
672 int vertcountunder = 0;
673 int vertcountover = 0;
674 List<int> vertscoplanar = new List<int>(); // existing vertex members of convex that are coplanar
675 List<int> edgesplit = new List<int>(); // existing edges that members of convex that cross the splitplane
676
677 Debug.Assert(convex.edges.Count < 480);
678
679 EdgeFlag[] edgeflag = new EdgeFlag[512];
680 VertFlag[] vertflag = new VertFlag[256];
681 PlaneFlag[] planeflag = new PlaneFlag[128];
682 ConvexH.HalfEdge[] tmpunderedges = new ConvexH.HalfEdge[512];
683 Plane[] tmpunderplanes = new Plane[128];
684 Coplanar[] coplanaredges = new Coplanar[512];
685 int coplanaredges_num = 0;
686
687 List<float3> createdverts = new List<float3>();
688
689 // do the side-of-plane tests
690 for (i = 0; i < convex.vertices.Count; i++)
691 {
692 vertflag[i].planetest = (byte)PlaneTest(slice, convex.vertices[i], planetestepsilon);
693 if (vertflag[i].planetest == (0))
694 {
695 // ? vertscoplanar.Add(i);
696 vertflag[i].undermap = (byte)vertcountunder++;
697 vertflag[i].overmap = (byte)vertcountover++;
698 }
699 else if (vertflag[i].planetest == (1))
700 {
701 vertflag[i].undermap = (byte)vertcountunder++;
702 }
703 else
704 {
705 Debug.Assert(vertflag[i].planetest == (2));
706 vertflag[i].overmap = (byte)vertcountover++;
707 vertflag[i].undermap = 255; // for debugging purposes
708 }
709 }
710 int vertcountunderold = vertcountunder; // for debugging only
711
712 int under_edge_count = 0;
713 int underplanescount = 0;
714 int e0 = 0;
715
716 for (int currentplane = 0; currentplane < convex.facets.Count; currentplane++)
717 {
718 int estart = e0;
719 int enextface = 0;
720 int planeside = 0;
721 int e1 = e0 + 1;
722 int vout = -1;
723 int vin = -1;
724 int coplanaredge = -1;
725 do
726 {
727
728 if (e1 >= convex.edges.Count || convex.edges[e1].p != currentplane)
729 {
730 enextface = e1;
731 e1 = estart;
732 }
733 ConvexH.HalfEdge edge0 = convex.edges[e0];
734 ConvexH.HalfEdge edge1 = convex.edges[e1];
735 ConvexH.HalfEdge edgea = convex.edges[edge0.ea];
736
737 planeside |= vertflag[edge0.v].planetest;
738 //if((vertflag[edge0.v].planetest & vertflag[edge1.v].planetest) == COPLANAR) {
739 // assert(ecop==-1);
740 // ecop=e;
741 //}
742
743 if (vertflag[edge0.v].planetest == (2) && vertflag[edge1.v].planetest == (2))
744 {
745 // both endpoints over plane
746 edgeflag[e0].undermap = -1;
747 }
748 else if ((vertflag[edge0.v].planetest | vertflag[edge1.v].planetest) == (1))
749 {
750 // at least one endpoint under, the other coplanar or under
751
752 edgeflag[e0].undermap = (short)under_edge_count;
753 tmpunderedges[under_edge_count].v = vertflag[edge0.v].undermap;
754 tmpunderedges[under_edge_count].p = (byte)underplanescount;
755 if (edge0.ea < e0)
756 {
757 // connect the neighbors
758 Debug.Assert(edgeflag[edge0.ea].undermap != -1);
759 tmpunderedges[under_edge_count].ea = edgeflag[edge0.ea].undermap;
760 tmpunderedges[edgeflag[edge0.ea].undermap].ea = (short)under_edge_count;
761 }
762 under_edge_count++;
763 }
764 else if ((vertflag[edge0.v].planetest | vertflag[edge1.v].planetest) == (0))
765 {
766 // both endpoints coplanar
767 // must check a 3rd point to see if UNDER
768 int e2 = e1 + 1;
769 if (e2 >= convex.edges.Count || convex.edges[e2].p != currentplane)
770 {
771 e2 = estart;
772 }
773 Debug.Assert(convex.edges[e2].p == currentplane);
774 ConvexH.HalfEdge edge2 = convex.edges[e2];
775 if (vertflag[edge2.v].planetest == (1))
776 {
777
778 edgeflag[e0].undermap = (short)under_edge_count;
779 tmpunderedges[under_edge_count].v = vertflag[edge0.v].undermap;
780 tmpunderedges[under_edge_count].p = (byte)underplanescount;
781 tmpunderedges[under_edge_count].ea = -1;
782 // make sure this edge is added to the "coplanar" list
783 coplanaredge = under_edge_count;
784 vout = vertflag[edge0.v].undermap;
785 vin = vertflag[edge1.v].undermap;
786 under_edge_count++;
787 }
788 else
789 {
790 edgeflag[e0].undermap = -1;
791 }
792 }
793 else if (vertflag[edge0.v].planetest == (1) && vertflag[edge1.v].planetest == (2))
794 {
795 // first is under 2nd is over
796
797 edgeflag[e0].undermap = (short)under_edge_count;
798 tmpunderedges[under_edge_count].v = vertflag[edge0.v].undermap;
799 tmpunderedges[under_edge_count].p = (byte)underplanescount;
800 if (edge0.ea < e0)
801 {
802 Debug.Assert(edgeflag[edge0.ea].undermap != -1);
803 // connect the neighbors
804 tmpunderedges[under_edge_count].ea = edgeflag[edge0.ea].undermap;
805 tmpunderedges[edgeflag[edge0.ea].undermap].ea = (short)under_edge_count;
806 vout = tmpunderedges[edgeflag[edge0.ea].undermap].v;
807 }
808 else
809 {
810 Plane p0 = convex.facets[edge0.p];
811 Plane pa = convex.facets[edgea.p];
812 createdverts.Add(ThreePlaneIntersection(p0, pa, slice));
813 //createdverts.Add(PlaneProject(slice,PlaneLineIntersection(slice,convex.vertices[edge0.v],convex.vertices[edgea.v])));
814 //createdverts.Add(PlaneLineIntersection(slice,convex.vertices[edge0.v],convex.vertices[edgea.v]));
815 vout = vertcountunder++;
816 }
817 under_edge_count++;
818 /// hmmm something to think about: i might be able to output this edge regarless of
819 // wheter or not we know v-in yet. ok i;ll try this now:
820 tmpunderedges[under_edge_count].v = (byte)vout;
821 tmpunderedges[under_edge_count].p = (byte)underplanescount;
822 tmpunderedges[under_edge_count].ea = -1;
823 coplanaredge = under_edge_count;
824 under_edge_count++;
825
826 if (vin != -1)
827 {
828 // we previously processed an edge where we came under
829 // now we know about vout as well
830
831 // ADD THIS EDGE TO THE LIST OF EDGES THAT NEED NEIGHBOR ON PARTITION PLANE!!
832 }
833
834 }
835 else if (vertflag[edge0.v].planetest == (0) && vertflag[edge1.v].planetest == (2))
836 {
837 // first is coplanar 2nd is over
838
839 edgeflag[e0].undermap = -1;
840 vout = vertflag[edge0.v].undermap;
841 // I hate this but i have to make sure part of this face is UNDER before ouputting this vert
842 int k = estart;
843 Debug.Assert(edge0.p == currentplane);
844 while (!((planeside & 1) != 0) && k < convex.edges.Count && convex.edges[k].p == edge0.p)
845 {
846 planeside |= vertflag[convex.edges[k].v].planetest;
847 k++;
848 }
849 if ((planeside & 1) != 0)
850 {
851 tmpunderedges[under_edge_count].v = (byte)vout;
852 tmpunderedges[under_edge_count].p = (byte)underplanescount;
853 tmpunderedges[under_edge_count].ea = -1;
854 coplanaredge = under_edge_count; // hmmm should make a note of the edge # for later on
855 under_edge_count++;
856
857 }
858 }
859 else if (vertflag[edge0.v].planetest == (2) && vertflag[edge1.v].planetest == (1))
860 {
861 // first is over next is under
862 // new vertex!!!
863 Debug.Assert(vin == -1);
864 if (e0 < edge0.ea)
865 {
866 Plane p0 = convex.facets[edge0.p];
867 Plane pa = convex.facets[edgea.p];
868 createdverts.Add(ThreePlaneIntersection(p0, pa, slice));
869 //createdverts.Add(PlaneLineIntersection(slice,convex.vertices[edge0.v],convex.vertices[edgea.v]));
870 //createdverts.Add(PlaneProject(slice,PlaneLineIntersection(slice,convex.vertices[edge0.v],convex.vertices[edgea.v])));
871 vin = vertcountunder++;
872 }
873 else
874 {
875 // find the new vertex that was created by edge[edge0.ea]
876 int nea = edgeflag[edge0.ea].undermap;
877 Debug.Assert(tmpunderedges[nea].p == tmpunderedges[nea + 1].p);
878 vin = tmpunderedges[nea + 1].v;
879 Debug.Assert(vin < vertcountunder);
880 Debug.Assert(vin >= vertcountunderold); // for debugging only
881 }
882 if (vout != -1)
883 {
884 // we previously processed an edge where we went over
885 // now we know vin too
886 // ADD THIS EDGE TO THE LIST OF EDGES THAT NEED NEIGHBOR ON PARTITION PLANE!!
887 }
888 // output edge
889 tmpunderedges[under_edge_count].v = (byte)vin;
890 tmpunderedges[under_edge_count].p = (byte)underplanescount;
891 edgeflag[e0].undermap = (short)under_edge_count;
892 if (e0 > edge0.ea)
893 {
894 Debug.Assert(edgeflag[edge0.ea].undermap != -1);
895 // connect the neighbors
896 tmpunderedges[under_edge_count].ea = edgeflag[edge0.ea].undermap;
897 tmpunderedges[edgeflag[edge0.ea].undermap].ea = (short)under_edge_count;
898 }
899 Debug.Assert(edgeflag[e0].undermap == under_edge_count);
900 under_edge_count++;
901 }
902 else if (vertflag[edge0.v].planetest == (2) && vertflag[edge1.v].planetest == (0))
903 {
904 // first is over next is coplanar
905
906 edgeflag[e0].undermap = -1;
907 vin = vertflag[edge1.v].undermap;
908 Debug.Assert(vin != -1);
909 if (vout != -1)
910 {
911 // we previously processed an edge where we came under
912 // now we know both endpoints
913 // ADD THIS EDGE TO THE LIST OF EDGES THAT NEED NEIGHBOR ON PARTITION PLANE!!
914 }
915
916 }
917 else
918 {
919 Debug.Assert(false);
920 }
921
922
923 e0 = e1;
924 e1++; // do the modulo at the beginning of the loop
925
926 } while (e0 != estart);
927 e0 = enextface;
928 if ((planeside & 1) != 0)
929 {
930 planeflag[currentplane].undermap = (byte)underplanescount;
931 tmpunderplanes[underplanescount] = convex.facets[currentplane];
932 underplanescount++;
933 }
934 else
935 {
936 planeflag[currentplane].undermap = 0;
937 }
938 if (vout >= 0 && (planeside & 1) != 0)
939 {
940 Debug.Assert(vin >= 0);
941 Debug.Assert(coplanaredge >= 0);
942 Debug.Assert(coplanaredge != 511);
943 coplanaredges[coplanaredges_num].ea = (ushort)coplanaredge;
944 coplanaredges[coplanaredges_num].v0 = (byte)vin;
945 coplanaredges[coplanaredges_num].v1 = (byte)vout;
946 coplanaredges_num++;
947 }
948 }
949
950 // add the new plane to the mix:
951 if (coplanaredges_num > 0)
952 {
953 tmpunderplanes[underplanescount++] = slice;
954 }
955 for (i = 0; i < coplanaredges_num - 1; i++)
956 {
957 if (coplanaredges[i].v1 != coplanaredges[i + 1].v0)
958 {
959 int j = 0;
960 for (j = i + 2; j < coplanaredges_num; j++)
961 {
962 if (coplanaredges[i].v1 == coplanaredges[j].v0)
963 {
964 Coplanar tmp = coplanaredges[i + 1];
965 coplanaredges[i + 1] = coplanaredges[j];
966 coplanaredges[j] = tmp;
967 break;
968 }
969 }
970 if (j >= coplanaredges_num)
971 {
972 Debug.Assert(j < coplanaredges_num);
973 return null;
974 }
975 }
976 }
977
978 ConvexH punder = new ConvexH(vertcountunder, under_edge_count + coplanaredges_num, underplanescount);
979 ConvexH under = punder;
980
981 {
982 int k = 0;
983 for (i = 0; i < convex.vertices.Count; i++)
984 {
985 if (vertflag[i].planetest != (2))
986 {
987 under.vertices[k++] = convex.vertices[i];
988 }
989 }
990 i = 0;
991 while (k < vertcountunder)
992 {
993 under.vertices[k++] = createdverts[i++];
994 }
995 Debug.Assert(i == createdverts.Count);
996 }
997
998 for (i = 0; i < coplanaredges_num; i++)
999 {
1000 ConvexH.HalfEdge edge = under.edges[under_edge_count + i];
1001 edge.p = (byte)(underplanescount - 1);
1002 edge.ea = (short)coplanaredges[i].ea;
1003 edge.v = (byte)coplanaredges[i].v0;
1004 under.edges[under_edge_count + i] = edge;
1005
1006 tmpunderedges[coplanaredges[i].ea].ea = (short)(under_edge_count + i);
1007 }
1008
1009 under.edges = new List<ConvexH.HalfEdge>(tmpunderedges);
1010 under.facets = new List<Plane>(tmpunderplanes);
1011 return punder;
1012 }
1013
1014 public static ConvexH ConvexHDup(ConvexH src)
1015 {
1016 ConvexH dst = new ConvexH(src.vertices.Count, src.edges.Count, src.facets.Count);
1017 dst.vertices = new List<float3>(src.vertices.Count);
1018 foreach (float3 f in src.vertices)
1019 dst.vertices.Add(new float3(f));
1020 dst.edges = new List<ConvexH.HalfEdge>(src.edges.Count);
1021 foreach (ConvexH.HalfEdge e in src.edges)
1022 dst.edges.Add(new ConvexH.HalfEdge(e));
1023 dst.facets = new List<Plane>(src.facets.Count);
1024 foreach (Plane p in src.facets)
1025 dst.facets.Add(new Plane(p));
1026 return dst;
1027 }
1028
1029 public static int candidateplane(List<Plane> planes, int planes_count, ConvexH convex, float epsilon)
1030 {
1031 int p = 0;
1032 float md = 0;
1033 int i;
1034 for (i = 0; i < planes_count; i++)
1035 {
1036 float d = 0;
1037 for (int j = 0; j < convex.vertices.Count; j++)
1038 {
1039 d = Math.Max(d, float3.dot(convex.vertices[j], planes[i].normal) + planes[i].dist);
1040 }
1041 if (i == 0 || d > md)
1042 {
1043 p = i;
1044 md = d;
1045 }
1046 }
1047 return (md > epsilon) ? p : -1;
1048 }
1049
1050 public static float3 orth(float3 v)
1051 {
1052 float3 a = float3.cross(v, new float3(0f, 0f, 1f));
1053 float3 b = float3.cross(v, new float3(0f, 1f, 0f));
1054 return float3.normalize((float3.magnitude(a) > float3.magnitude(b)) ? a : b);
1055 }
1056
1057 public static int maxdir(List<float3> p, int count, float3 dir)
1058 {
1059 Debug.Assert(count != 0);
1060 int m = 0;
1061 float currDotm = float3.dot(p[0], dir);
1062 for (int i = 1; i < count; i++)
1063 {
1064 float currDoti = float3.dot(p[i], dir);
1065 if (currDoti > currDotm)
1066 {
1067 currDotm = currDoti;
1068 m = i;
1069 }
1070 }
1071 return m;
1072 }
1073
1074 public static int maxdirfiltered(List<float3> p, int count, float3 dir, byte[] allow)
1075 {
1076 //Debug.Assert(count != 0);
1077 int m = 0;
1078 float currDotm = float3.dot(p[0], dir);
1079 float currDoti;
1080
1081 while (allow[m] == 0)
1082 m++;
1083
1084 for (int i = 1; i < count; i++)
1085 {
1086 if (allow[i] != 0)
1087 {
1088 currDoti = float3.dot(p[i], dir);
1089 if (currDoti > currDotm)
1090 {
1091 currDotm = currDoti;
1092 m = i;
1093 }
1094 }
1095 }
1096 //Debug.Assert(m != -1);
1097 return m;
1098 }
1099
1100 public static int maxdirsterid(List<float3> p, int count, float3 dir, byte[] allow)
1101 {
1102 int m = -1;
1103 while (m == -1)
1104 {
1105 m = maxdirfiltered(p, count, dir, allow);
1106 if (allow[m] == 3)
1107 return m;
1108 float3 u = orth(dir);
1109 float3 v = float3.cross(u, dir);
1110 int ma = -1;
1111 for (float x = 0.0f; x <= 360.0f; x += 45.0f)
1112 {
1113 int mb;
1114 {
1115 float s = (float)Math.Sin((3.14159264f / 180.0f) * (x));
1116 float c = (float)Math.Cos((3.14159264f / 180.0f) * (x));
1117 mb = maxdirfiltered(p, count, dir + (u * s + v * c) * 0.025f, allow);
1118 }
1119 if (ma == m && mb == m)
1120 {
1121 allow[m] = 3;
1122 return m;
1123 }
1124 if (ma != -1 && ma != mb) // Yuck - this is really ugly
1125 {
1126 int mc = ma;
1127 for (float xx = x - 40.0f; xx <= x; xx += 5.0f)
1128 {
1129 float s = (float)Math.Sin((3.14159264f / 180.0f) * (xx));
1130 float c = (float)Math.Cos((3.14159264f / 180.0f) * (xx));
1131 int md = maxdirfiltered(p, count, dir + (u * s + v * c) * 0.025f, allow);
1132 if (mc == m && md == m)
1133 {
1134 allow[m] = 3;
1135 return m;
1136 }
1137 mc = md;
1138 }
1139 }
1140 ma = mb;
1141 }
1142 allow[m] = 0;
1143 m = -1;
1144 }
1145
1146 Debug.Assert(false);
1147 return m;
1148 }
1149
1150 public static int4 FindSimplex(List<float3> verts, byte[] allow)
1151 {
1152 float3[] basis = new float3[3];
1153 basis[0] = new float3(0.01f, 0.02f, 1.0f);
1154 int p0 = maxdirsterid(verts, verts.Count, basis[0], allow);
1155 int p1 = maxdirsterid(verts, verts.Count, -basis[0], allow);
1156 basis[0] = verts[p0] - verts[p1];
1157 if (p0 == p1 || basis[0] == new float3(0, 0, 0))
1158 return new int4(-1, -1, -1, -1);
1159 basis[1] = float3.cross(new float3(1, 0.02f, 0), basis[0]);
1160 basis[2] = float3.cross(new float3(-0.02f, 1, 0), basis[0]);
1161 basis[1] = float3.normalize((float3.magnitude(basis[1]) > float3.magnitude(basis[2])) ? basis[1] : basis[2]);
1162 int p2 = maxdirsterid(verts, verts.Count, basis[1], allow);
1163 if (p2 == p0 || p2 == p1)
1164 {
1165 p2 = maxdirsterid(verts, verts.Count, -basis[1], allow);
1166 }
1167 if (p2 == p0 || p2 == p1)
1168 return new int4(-1, -1, -1, -1);
1169 basis[1] = verts[p2] - verts[p0];
1170 basis[2] = float3.normalize(float3.cross(basis[1], basis[0]));
1171 int p3 = maxdirsterid(verts, verts.Count, basis[2], allow);
1172 if (p3 == p0 || p3 == p1 || p3 == p2)
1173 p3 = maxdirsterid(verts, verts.Count, -basis[2], allow);
1174 if (p3 == p0 || p3 == p1 || p3 == p2)
1175 return new int4(-1, -1, -1, -1);
1176 Debug.Assert(!(p0 == p1 || p0 == p2 || p0 == p3 || p1 == p2 || p1 == p3 || p2 == p3));
1177 if (float3.dot(verts[p3] - verts[p0], float3.cross(verts[p1] - verts[p0], verts[p2] - verts[p0])) < 0)
1178 {
1179 Swap(ref p2, ref p3);
1180 }
1181 return new int4(p0, p1, p2, p3);
1182 }
1183
1184 public static float GetDist(float px, float py, float pz, float3 p2)
1185 {
1186 float dx = px - p2.x;
1187 float dy = py - p2.y;
1188 float dz = pz - p2.z;
1189
1190 return dx * dx + dy * dy + dz * dz;
1191 }
1192
1193 public static void ReleaseHull(PHullResult result)
1194 {
1195 if (result.Indices != null)
1196 result.Indices = null;
1197 if (result.Vertices != null)
1198 result.Vertices = null;
1199 }
1200
1201 public static int calchullgen(List<float3> verts, int vlimit, List<HullTriangle> tris)
1202 {
1203 if (verts.Count < 4)
1204 return 0;
1205 if (vlimit == 0)
1206 vlimit = 1000000000;
1207 int j;
1208 float3 bmin = new float3(verts[0]);
1209 float3 bmax = new float3(verts[0]);
1210 List<int> isextreme = new List<int>(verts.Count);
1211 byte[] allow = new byte[verts.Count];
1212 for (j = 0; j < verts.Count; j++)
1213 {
1214 allow[j] = 1;
1215 isextreme.Add(0);
1216 bmin = float3.VectorMin(bmin, verts[j]);
1217 bmax = float3.VectorMax(bmax, verts[j]);
1218 }
1219 float epsilon = float3.magnitude(bmax - bmin) * 0.001f;
1220
1221 int4 p = FindSimplex(verts, allow);
1222 if (p.x == -1) // simplex failed
1223 return 0;
1224
1225 float3 center = (verts[p[0]] + verts[p[1]] + verts[p[2]] + verts[p[3]]) / 4.0f; // a valid interior point
1226 HullTriangle t0 = new HullTriangle(p[2], p[3], p[1], tris);
1227 t0.n = new int3(2, 3, 1);
1228 HullTriangle t1 = new HullTriangle(p[3], p[2], p[0], tris);
1229 t1.n = new int3(3, 2, 0);
1230 HullTriangle t2 = new HullTriangle(p[0], p[1], p[3], tris);
1231 t2.n = new int3(0, 1, 3);
1232 HullTriangle t3 = new HullTriangle(p[1], p[0], p[2], tris);
1233 t3.n = new int3(1, 0, 2);
1234 isextreme[p[0]] = isextreme[p[1]] = isextreme[p[2]] = isextreme[p[3]] = 1;
1235 checkit(t0, tris);
1236 checkit(t1, tris);
1237 checkit(t2, tris);
1238 checkit(t3, tris);
1239
1240 for (j = 0; j < tris.Count; j++)
1241 {
1242 HullTriangle t = tris[j];
1243 Debug.Assert((object)t != null);
1244 Debug.Assert(t.vmax < 0);
1245 float3 n = TriNormal(verts[(t)[0]], verts[(t)[1]], verts[(t)[2]]);
1246 t.vmax = maxdirsterid(verts, verts.Count, n, allow);
1247 t.rise = float3.dot(n, verts[t.vmax] - verts[(t)[0]]);
1248 }
1249 HullTriangle te;
1250 vlimit -= 4;
1251 while (vlimit > 0 && (te = extrudable(epsilon, tris)) != null)
1252 {
1253 int3 ti = te;
1254 int v = te.vmax;
1255 Debug.Assert(isextreme[v] == 0); // wtf we've already done this vertex
1256 isextreme[v] = 1;
1257 //if(v==p0 || v==p1 || v==p2 || v==p3) continue; // done these already
1258 j = tris.Count;
1259 while (j-- != 0)
1260 {
1261 if (tris.Count <= j || (object)tris[j] == null)
1262 continue;
1263 int3 t = tris[j];
1264 if (above(verts, t, verts[v], 0.01f * epsilon))
1265 {
1266 extrude(tris[j], v, tris);
1267 }
1268 }
1269 // now check for those degenerate cases where we have a flipped triangle or a really skinny triangle
1270 j = tris.Count;
1271 while (j-- != 0)
1272 {
1273 if (tris.Count <= j || (object)tris[j] == null)
1274 continue;
1275 if (!hasvert(tris[j], v))
1276 break;
1277 int3 nt = tris[j];
1278 if (above(verts, nt, center, 0.01f * epsilon) || float3.magnitude(float3.cross(verts[nt[1]] - verts[nt[0]], verts[nt[2]] - verts[nt[1]])) < epsilon * epsilon * 0.1f)
1279 {
1280 HullTriangle nb = tris[tris[j].n[0]];
1281 Debug.Assert(nb != null);
1282 Debug.Assert(!hasvert(nb, v));
1283 Debug.Assert(nb.id < j);
1284 extrude(nb, v, tris);
1285 j = tris.Count;
1286 }
1287 }
1288 j = tris.Count;
1289 while (j-- != 0)
1290 {
1291 HullTriangle t = tris[j];
1292 if (t == null)
1293 continue;
1294 if (t.vmax >= 0)
1295 break;
1296 float3 n = TriNormal(verts[(t)[0]], verts[(t)[1]], verts[(t)[2]]);
1297 t.vmax = maxdirsterid(verts, verts.Count, n, allow);
1298 if (isextreme[t.vmax] != 0)
1299 {
1300 t.vmax = -1; // already done that vertex - algorithm needs to be able to terminate.
1301 }
1302 else
1303 {
1304 t.rise = float3.dot(n, verts[t.vmax] - verts[(t)[0]]);
1305 }
1306 }
1307 vlimit--;
1308 }
1309 return 1;
1310 }
1311
1312 public static bool calchull(List<float3> verts, out List<int> tris_out, int vlimit, List<HullTriangle> tris)
1313 {
1314 tris_out = null;
1315
1316 int rc = calchullgen(verts, vlimit, tris);
1317 if (rc == 0)
1318 return false;
1319 List<int> ts = new List<int>();
1320 for (int i = 0; i < tris.Count; i++)
1321 {
1322 if ((object)tris[i] != null)
1323 {
1324 for (int j = 0; j < 3; j++)
1325 ts.Add((tris[i])[j]);
1326 tris[i] = null;
1327 }
1328 }
1329
1330 tris_out = ts;
1331 tris.Clear();
1332 return true;
1333 }
1334
1335 public static int calchullpbev(List<float3> verts, int vlimit, out List<Plane> planes, float bevangle, List<HullTriangle> tris)
1336 {
1337 int i;
1338 int j;
1339 planes = new List<Plane>();
1340 int rc = calchullgen(verts, vlimit, tris);
1341 if (rc == 0)
1342 return 0;
1343 for (i = 0; i < tris.Count; i++)
1344 {
1345 if (tris[i] != null)
1346 {
1347 Plane p = new Plane();
1348 HullTriangle t = tris[i];
1349 p.normal = TriNormal(verts[(t)[0]], verts[(t)[1]], verts[(t)[2]]);
1350 p.dist = -float3.dot(p.normal, verts[(t)[0]]);
1351 planes.Add(p);
1352 for (j = 0; j < 3; j++)
1353 {
1354 if (t.n[j] < t.id)
1355 continue;
1356 HullTriangle s = tris[t.n[j]];
1357 float3 snormal = TriNormal(verts[(s)[0]], verts[(s)[1]], verts[(s)[2]]);
1358 if (float3.dot(snormal, p.normal) >= Math.Cos(bevangle * (3.14159264f / 180.0f)))
1359 continue;
1360 float3 n = float3.normalize(snormal + p.normal);
1361 planes.Add(new Plane(n, -float3.dot(n, verts[maxdir(verts, verts.Count, n)])));
1362 }
1363 }
1364 }
1365
1366 tris.Clear();
1367 return 1;
1368 }
1369
1370 public static int overhull(List<Plane> planes, List<float3> verts, int maxplanes, out List<float3> verts_out, out List<int> faces_out, float inflate)
1371 {
1372 verts_out = null;
1373 faces_out = null;
1374
1375 int i;
1376 int j;
1377 if (verts.Count < 4)
1378 return 0;
1379 maxplanes = Math.Min(maxplanes, planes.Count);
1380 float3 bmin = new float3(verts[0]);
1381 float3 bmax = new float3(verts[0]);
1382 for (i = 0; i < verts.Count; i++)
1383 {
1384 bmin = float3.VectorMin(bmin, verts[i]);
1385 bmax = float3.VectorMax(bmax, verts[i]);
1386 }
1387 // float diameter = magnitude(bmax-bmin);
1388 // inflate *=diameter; // RELATIVE INFLATION
1389 bmin -= new float3(inflate, inflate, inflate);
1390 bmax += new float3(inflate, inflate, inflate);
1391 for (i = 0; i < planes.Count; i++)
1392 {
1393 planes[i].dist -= inflate;
1394 }
1395 float3 emin = new float3(bmin);
1396 float3 emax = new float3(bmax);
1397 float epsilon = float3.magnitude(emax - emin) * 0.025f;
1398 float planetestepsilon = float3.magnitude(emax - emin) * (0.001f);
1399 // todo: add bounding cube planes to force bevel. or try instead not adding the diameter expansion ??? must think.
1400 // ConvexH *convex = ConvexHMakeCube(bmin - float3(diameter,diameter,diameter),bmax+float3(diameter,diameter,diameter));
1401 ConvexH c = ConvexHMakeCube(new float3(bmin), new float3(bmax));
1402 int k;
1403 while (maxplanes-- != 0 && (k = candidateplane(planes, planes.Count, c, epsilon)) >= 0)
1404 {
1405 ConvexH tmp = c;
1406 c = ConvexHCrop(ref tmp, planes[k], planetestepsilon);
1407 if (c == null) // might want to debug this case better!!!
1408 {
1409 c = tmp;
1410 break;
1411 }
1412 if (AssertIntact(c, planetestepsilon) == false) // might want to debug this case better too!!!
1413 {
1414 c = tmp;
1415 break;
1416 }
1417 tmp.edges = null;
1418 tmp.facets = null;
1419 tmp.vertices = null;
1420 }
1421
1422 Debug.Assert(AssertIntact(c, planetestepsilon));
1423 //return c;
1424 //C++ TO C# CONVERTER TODO TASK: The memory management function 'malloc' has no equivalent in C#:
1425 faces_out = new List<int>(); //(int)malloc(sizeof(int) * (1 + c.facets.Count + c.edges.Count)); // new int[1+c->facets.count+c->edges.count];
1426 int faces_count_out = 0;
1427 i = 0;
1428 faces_out[faces_count_out++] = -1;
1429 k = 0;
1430 while (i < c.edges.Count)
1431 {
1432 j = 1;
1433 while (j + i < c.edges.Count && c.edges[i].p == c.edges[i + j].p)
1434 {
1435 j++;
1436 }
1437 faces_out[faces_count_out++] = j;
1438 while (j-- != 0)
1439 {
1440 faces_out[faces_count_out++] = c.edges[i].v;
1441 i++;
1442 }
1443 k++;
1444 }
1445 faces_out[0] = k; // number of faces.
1446 Debug.Assert(k == c.facets.Count);
1447 Debug.Assert(faces_count_out == 1 + c.facets.Count + c.edges.Count);
1448 verts_out = c.vertices; // new float3[c->vertices.count];
1449 int verts_count_out = c.vertices.Count;
1450 for (i = 0; i < c.vertices.Count; i++)
1451 {
1452 verts_out[i] = new float3(c.vertices[i]);
1453 }
1454
1455 c.edges = null;
1456 c.facets = null;
1457 c.vertices = null;
1458 return 1;
1459 }
1460
1461 public static int overhullv(List<float3> verts, int maxplanes, out List<float3> verts_out, out List<int> faces_out, float inflate, float bevangle, int vlimit, List<HullTriangle> tris)
1462 {
1463 verts_out = null;
1464 faces_out = null;
1465
1466 if (verts.Count == 0)
1467 return 0;
1468 List<Plane> planes = new List<Plane>();
1469 int rc = calchullpbev(verts, vlimit, out planes, bevangle, tris);
1470 if (rc == 0)
1471 return 0;
1472 return overhull(planes, verts, maxplanes, out verts_out, out faces_out, inflate);
1473 }
1474
1475 public static void addPoint(ref uint vcount, List<float3> p, float x, float y, float z)
1476 {
1477 p.Add(new float3(x, y, z));
1478 vcount++;
1479 }
1480
1481 public static bool ComputeHull(List<float3> vertices, ref PHullResult result, int vlimit, float inflate)
1482 {
1483 List<HullTriangle> tris = new List<HullTriangle>();
1484 List<int> faces;
1485 List<float3> verts_out;
1486
1487 if (inflate == 0.0f)
1488 {
1489 List<int> tris_out;
1490 bool ret = calchull(vertices, out tris_out, vlimit, tris);
1491 if (ret == false)
1492 return false;
1493
1494 result.Indices = tris_out;
1495 result.Vertices = vertices;
1496 return true;
1497 }
1498 else
1499 {
1500 int ret = overhullv(vertices, 35, out verts_out, out faces, inflate, 120.0f, vlimit, tris);
1501 if (ret == 0)
1502 return false;
1503
1504 List<int3> tris2 = new List<int3>();
1505 int n = faces[0];
1506 int k = 1;
1507 for (int i = 0; i < n; i++)
1508 {
1509 int pn = faces[k++];
1510 for (int j = 2; j < pn; j++)
1511 tris2.Add(new int3(faces[k], faces[k + j - 1], faces[k + j]));
1512 k += pn;
1513 }
1514 Debug.Assert(tris2.Count == faces.Count - 1 - (n * 3));
1515
1516 result.Indices = new List<int>(tris2.Count * 3);
1517 for (int i = 0; i < tris2.Count; i++)
1518 {
1519 result.Indices.Add(tris2[i].x);
1520 result.Indices.Add(tris2[i].y);
1521 result.Indices.Add(tris2[i].z);
1522 }
1523 result.Vertices = verts_out;
1524
1525 return true;
1526 }
1527 }
1528
1529 private static bool CleanupVertices(List<float3> svertices, out List<float3> vertices, float normalepsilon, out float3 scale)
1530 {
1531 const float EPSILON = 0.000001f;
1532
1533 vertices = new List<float3>();
1534 scale = new float3(1f, 1f, 1f);
1535
1536 if (svertices.Count == 0)
1537 return false;
1538
1539 uint vcount = 0;
1540
1541 float[] recip = new float[3];
1542
1543 float[] bmin = { Single.MaxValue, Single.MaxValue, Single.MaxValue };
1544 float[] bmax = { Single.MinValue, Single.MinValue, Single.MinValue };
1545
1546 for (int i = 0; i < svertices.Count; i++)
1547 {
1548 float3 p = svertices[i];
1549
1550 for (int j = 0; j < 3; j++)
1551 {
1552 if (p[j] < bmin[j])
1553 bmin[j] = p[j];
1554 if (p[j] > bmax[j])
1555 bmax[j] = p[j];
1556 }
1557 }
1558
1559 float dx = bmax[0] - bmin[0];
1560 float dy = bmax[1] - bmin[1];
1561 float dz = bmax[2] - bmin[2];
1562
1563 float3 center = new float3();
1564
1565 center.x = dx * 0.5f + bmin[0];
1566 center.y = dy * 0.5f + bmin[1];
1567 center.z = dz * 0.5f + bmin[2];
1568
1569 if (dx < EPSILON || dy < EPSILON || dz < EPSILON || svertices.Count < 3)
1570 {
1571 float len = Single.MaxValue;
1572
1573 if (dx > EPSILON && dx < len)
1574 len = dx;
1575 if (dy > EPSILON && dy < len)
1576 len = dy;
1577 if (dz > EPSILON && dz < len)
1578 len = dz;
1579
1580 if (len == Single.MaxValue)
1581 {
1582 dx = dy = dz = 0.01f; // one centimeter
1583 }
1584 else
1585 {
1586 if (dx < EPSILON) // 1/5th the shortest non-zero edge.
1587 dx = len * 0.05f;
1588 if (dy < EPSILON)
1589 dy = len * 0.05f;
1590 if (dz < EPSILON)
1591 dz = len * 0.05f;
1592 }
1593
1594 float x1 = center[0] - dx;
1595 float x2 = center[0] + dx;
1596
1597 float y1 = center[1] - dy;
1598 float y2 = center[1] + dy;
1599
1600 float z1 = center[2] - dz;
1601 float z2 = center[2] + dz;
1602
1603 addPoint(ref vcount, vertices, x1, y1, z1);
1604 addPoint(ref vcount, vertices, x2, y1, z1);
1605 addPoint(ref vcount, vertices, x2, y2, z1);
1606 addPoint(ref vcount, vertices, x1, y2, z1);
1607 addPoint(ref vcount, vertices, x1, y1, z2);
1608 addPoint(ref vcount, vertices, x2, y1, z2);
1609 addPoint(ref vcount, vertices, x2, y2, z2);
1610 addPoint(ref vcount, vertices, x1, y2, z2);
1611
1612 return true; // return cube
1613 }
1614 else
1615 {
1616 scale.x = dx;
1617 scale.y = dy;
1618 scale.z = dz;
1619
1620 recip[0] = 1f / dx;
1621 recip[1] = 1f / dy;
1622 recip[2] = 1f / dz;
1623
1624 center.x *= recip[0];
1625 center.y *= recip[1];
1626 center.z *= recip[2];
1627 }
1628
1629 for (int i = 0; i < svertices.Count; i++)
1630 {
1631 float3 p = svertices[i];
1632
1633 float px = p[0];
1634 float py = p[1];
1635 float pz = p[2];
1636
1637 px = px * recip[0]; // normalize
1638 py = py * recip[1]; // normalize
1639 pz = pz * recip[2]; // normalize
1640
1641 if (true)
1642 {
1643 int j;
1644
1645 for (j = 0; j < vcount; j++)
1646 {
1647 float3 v = vertices[j];
1648
1649 float x = v[0];
1650 float y = v[1];
1651 float z = v[2];
1652
1653 float dx1 = Math.Abs(x - px);
1654 float dy1 = Math.Abs(y - py);
1655 float dz1 = Math.Abs(z - pz);
1656
1657 if (dx1 < normalepsilon && dy1 < normalepsilon && dz1 < normalepsilon)
1658 {
1659 // ok, it is close enough to the old one
1660 // now let us see if it is further from the center of the point cloud than the one we already recorded.
1661 // in which case we keep this one instead.
1662 float dist1 = GetDist(px, py, pz, center);
1663 float dist2 = GetDist(v[0], v[1], v[2], center);
1664
1665 if (dist1 > dist2)
1666 {
1667 v.x = px;
1668 v.y = py;
1669 v.z = pz;
1670 }
1671
1672 break;
1673 }
1674 }
1675
1676 if (j == vcount)
1677 {
1678 float3 dest = new float3(px, py, pz);
1679 vertices.Add(dest);
1680 vcount++;
1681 }
1682 }
1683 }
1684
1685 // ok..now make sure we didn't prune so many vertices it is now invalid.
1686 if (true)
1687 {
1688 float[] bmin2 = { Single.MaxValue, Single.MaxValue, Single.MaxValue };
1689 float[] bmax2 = { Single.MinValue, Single.MinValue, Single.MinValue };
1690
1691 for (int i = 0; i < vcount; i++)
1692 {
1693 float3 p = vertices[i];
1694 for (int j = 0; j < 3; j++)
1695 {
1696 if (p[j] < bmin2[j])
1697 bmin2[j] = p[j];
1698 if (p[j] > bmax2[j])
1699 bmax2[j] = p[j];
1700 }
1701 }
1702
1703 float dx2 = bmax2[0] - bmin2[0];
1704 float dy2 = bmax2[1] - bmin2[1];
1705 float dz2 = bmax2[2] - bmin2[2];
1706
1707 if (dx2 < EPSILON || dy2 < EPSILON || dz2 < EPSILON || vcount < 3)
1708 {
1709 float cx = dx2 * 0.5f + bmin2[0];
1710 float cy = dy2 * 0.5f + bmin2[1];
1711 float cz = dz2 * 0.5f + bmin2[2];
1712
1713 float len = Single.MaxValue;
1714
1715 if (dx2 >= EPSILON && dx2 < len)
1716 len = dx2;
1717 if (dy2 >= EPSILON && dy2 < len)
1718 len = dy2;
1719 if (dz2 >= EPSILON && dz2 < len)
1720 len = dz2;
1721
1722 if (len == Single.MaxValue)
1723 {
1724 dx2 = dy2 = dz2 = 0.01f; // one centimeter
1725 }
1726 else
1727 {
1728 if (dx2 < EPSILON) // 1/5th the shortest non-zero edge.
1729 dx2 = len * 0.05f;
1730 if (dy2 < EPSILON)
1731 dy2 = len * 0.05f;
1732 if (dz2 < EPSILON)
1733 dz2 = len * 0.05f;
1734 }
1735
1736 float x1 = cx - dx2;
1737 float x2 = cx + dx2;
1738
1739 float y1 = cy - dy2;
1740 float y2 = cy + dy2;
1741
1742 float z1 = cz - dz2;
1743 float z2 = cz + dz2;
1744
1745 vcount = 0; // add box
1746
1747 addPoint(ref vcount, vertices, x1, y1, z1);
1748 addPoint(ref vcount, vertices, x2, y1, z1);
1749 addPoint(ref vcount, vertices, x2, y2, z1);
1750 addPoint(ref vcount, vertices, x1, y2, z1);
1751 addPoint(ref vcount, vertices, x1, y1, z2);
1752 addPoint(ref vcount, vertices, x2, y1, z2);
1753 addPoint(ref vcount, vertices, x2, y2, z2);
1754 addPoint(ref vcount, vertices, x1, y2, z2);
1755
1756 return true;
1757 }
1758 }
1759
1760 return true;
1761 }
1762
1763 private static void BringOutYourDead(List<float3> verts, out List<float3> overts, List<int> indices)
1764 {
1765 int[] used = new int[verts.Count];
1766 int ocount = 0;
1767
1768 overts = new List<float3>();
1769
1770 for (int i = 0; i < indices.Count; i++)
1771 {
1772 int v = indices[i]; // original array index
1773
1774 Debug.Assert(v >= 0 && v < verts.Count);
1775
1776 if (used[v] != 0) // if already remapped
1777 {
1778 indices[i] = used[v] - 1; // index to new array
1779 }
1780 else
1781 {
1782 indices[i] = ocount; // new index mapping
1783
1784 overts.Add(verts[v]); // copy old vert to new vert array
1785
1786 ocount++; // increment output vert count
1787
1788 Debug.Assert(ocount >= 0 && ocount <= verts.Count);
1789
1790 used[v] = ocount; // assign new index remapping
1791 }
1792 }
1793 }
1794
1795 public static HullError CreateConvexHull(HullDesc desc, ref HullResult result)
1796 {
1797 HullError ret = HullError.QE_FAIL;
1798
1799 PHullResult hr = new PHullResult();
1800
1801 uint vcount = (uint)desc.Vertices.Count;
1802 if (vcount < 8)
1803 vcount = 8;
1804
1805 List<float3> vsource;
1806 float3 scale = new float3();
1807
1808 bool ok = CleanupVertices(desc.Vertices, out vsource, desc.NormalEpsilon, out scale); // normalize point cloud, remove duplicates!
1809
1810 if (ok)
1811 {
1812 if (true) // scale vertices back to their original size.
1813 {
1814 for (int i = 0; i < vsource.Count; i++)
1815 {
1816 float3 v = vsource[i];
1817 v.x *= scale[0];
1818 v.y *= scale[1];
1819 v.z *= scale[2];
1820 }
1821 }
1822
1823 float skinwidth = 0;
1824 if (desc.HasHullFlag(HullFlag.QF_SKIN_WIDTH))
1825 skinwidth = desc.SkinWidth;
1826
1827 ok = ComputeHull(vsource, ref hr, (int)desc.MaxVertices, skinwidth);
1828
1829 if (ok)
1830 {
1831 List<float3> vscratch;
1832 BringOutYourDead(hr.Vertices, out vscratch, hr.Indices);
1833
1834 ret = HullError.QE_OK;
1835
1836 if (desc.HasHullFlag(HullFlag.QF_TRIANGLES)) // if he wants the results as triangle!
1837 {
1838 result.Polygons = false;
1839 result.Indices = hr.Indices;
1840 result.OutputVertices = vscratch;
1841 }
1842 else
1843 {
1844 result.Polygons = true;
1845 result.OutputVertices = vscratch;
1846
1847 if (true)
1848 {
1849 List<int> source = hr.Indices;
1850 List<int> dest = new List<int>();
1851 for (int i = 0; i < hr.Indices.Count / 3; i++)
1852 {
1853 dest.Add(3);
1854 dest.Add(source[i * 3 + 0]);
1855 dest.Add(source[i * 3 + 1]);
1856 dest.Add(source[i * 3 + 2]);
1857 }
1858
1859 result.Indices = dest;
1860 }
1861 }
1862 }
1863 }
1864
1865 return ret;
1866 }
1867 }
1868}
diff --git a/OpenSim/Region/Physics/ConvexDecompositionDotNet/LICENSE.txt b/OpenSim/Region/Physics/ConvexDecompositionDotNet/LICENSE.txt
new file mode 100644
index 0000000..714ae89
--- /dev/null
+++ b/OpenSim/Region/Physics/ConvexDecompositionDotNet/LICENSE.txt
@@ -0,0 +1,28 @@
1ConvexDecompositionDotNet
2-------------------------
3
4The MIT License
5
6Copyright (c) 2010 Intel Corporation.
7All rights reserved.
8
9Based on the convexdecomposition library from
10<http://codesuppository.googlecode.com> by John W. Ratcliff and Stan Melax.
11
12Permission is hereby granted, free of charge, to any person obtaining a copy
13of this software and associated documentation files (the "Software"), to deal
14in the Software without restriction, including without limitation the rights
15to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
16copies of the Software, and to permit persons to whom the Software is
17furnished to do so, subject to the following conditions:
18
19The above copyright notice and this permission notice shall be included in
20all copies or substantial portions of the Software.
21
22THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
23IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
24FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
25AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
26LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
27OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
28THE SOFTWARE.
diff --git a/OpenSim/Region/Physics/ConvexDecompositionDotNet/Plane.cs b/OpenSim/Region/Physics/ConvexDecompositionDotNet/Plane.cs
new file mode 100644
index 0000000..d099676
--- /dev/null
+++ b/OpenSim/Region/Physics/ConvexDecompositionDotNet/Plane.cs
@@ -0,0 +1,99 @@
1/* The MIT License
2 *
3 * Copyright (c) 2010 Intel Corporation.
4 * All rights reserved.
5 *
6 * Based on the convexdecomposition library from
7 * <http://codesuppository.googlecode.com> by John W. Ratcliff and Stan Melax.
8 *
9 * Permission is hereby granted, free of charge, to any person obtaining a copy
10 * of this software and associated documentation files (the "Software"), to deal
11 * in the Software without restriction, including without limitation the rights
12 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
13 * copies of the Software, and to permit persons to whom the Software is
14 * furnished to do so, subject to the following conditions:
15 *
16 * The above copyright notice and this permission notice shall be included in
17 * all copies or substantial portions of the Software.
18 *
19 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
20 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
21 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
22 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
23 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
24 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
25 * THE SOFTWARE.
26 */
27
28using System;
29
30namespace OpenSim.Region.Physics.ConvexDecompositionDotNet
31{
32 public class Plane
33 {
34 public float3 normal = new float3();
35 public float dist; // distance below origin - the D from plane equasion Ax+By+Cz+D=0
36
37 public Plane(float3 n, float d)
38 {
39 normal = new float3(n);
40 dist = d;
41 }
42
43 public Plane(Plane p)
44 {
45 normal = new float3(p.normal);
46 dist = p.dist;
47 }
48
49 public Plane()
50 {
51 dist = 0;
52 }
53
54 public void Transform(float3 position, Quaternion orientation)
55 {
56 // Transforms the plane to the space defined by the
57 // given position/orientation
58 float3 newNormal = Quaternion.Inverse(orientation) * normal;
59 float3 origin = Quaternion.Inverse(orientation) * (-normal * dist - position);
60
61 normal = newNormal;
62 dist = -float3.dot(newNormal, origin);
63 }
64
65 public override int GetHashCode()
66 {
67 return normal.GetHashCode() ^ dist.GetHashCode();
68 }
69
70 public override bool Equals(object obj)
71 {
72 Plane p = obj as Plane;
73 if (p == null)
74 return false;
75
76 return this == p;
77 }
78
79 public static bool operator ==(Plane a, Plane b)
80 {
81 return (a.normal == b.normal && a.dist == b.dist);
82 }
83
84 public static bool operator !=(Plane a, Plane b)
85 {
86 return !(a == b);
87 }
88
89 public static Plane PlaneFlip(Plane plane)
90 {
91 return new Plane(-plane.normal, -plane.dist);
92 }
93
94 public static bool coplanar(Plane a, Plane b)
95 {
96 return (a == b || a == PlaneFlip(b));
97 }
98 }
99}
diff --git a/OpenSim/Region/Physics/ConvexDecompositionDotNet/PlaneTri.cs b/OpenSim/Region/Physics/ConvexDecompositionDotNet/PlaneTri.cs
new file mode 100644
index 0000000..31f0182
--- /dev/null
+++ b/OpenSim/Region/Physics/ConvexDecompositionDotNet/PlaneTri.cs
@@ -0,0 +1,211 @@
1/* The MIT License
2 *
3 * Copyright (c) 2010 Intel Corporation.
4 * All rights reserved.
5 *
6 * Based on the convexdecomposition library from
7 * <http://codesuppository.googlecode.com> by John W. Ratcliff and Stan Melax.
8 *
9 * Permission is hereby granted, free of charge, to any person obtaining a copy
10 * of this software and associated documentation files (the "Software"), to deal
11 * in the Software without restriction, including without limitation the rights
12 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
13 * copies of the Software, and to permit persons to whom the Software is
14 * furnished to do so, subject to the following conditions:
15 *
16 * The above copyright notice and this permission notice shall be included in
17 * all copies or substantial portions of the Software.
18 *
19 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
20 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
21 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
22 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
23 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
24 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
25 * THE SOFTWARE.
26 */
27
28using System;
29using System.Collections.Generic;
30using System.Diagnostics;
31
32namespace OpenSim.Region.Physics.ConvexDecompositionDotNet
33{
34 public enum PlaneTriResult : int
35 {
36 PTR_FRONT,
37 PTR_BACK,
38 PTR_SPLIT
39 }
40
41 public static class PlaneTri
42 {
43 private static float DistToPt(float3 p, float4 plane)
44 {
45 return p.x * plane.x + p.y * plane.y + p.z * plane.z + plane.w;
46 }
47
48 private static PlaneTriResult getSidePlane(float3 p, float4 plane, float epsilon)
49 {
50 float d = DistToPt(p, plane);
51
52 if ((d + epsilon) > 0f)
53 return PlaneTriResult.PTR_FRONT; // it is 'in front' within the provided epsilon value.
54
55 return PlaneTriResult.PTR_BACK;
56 }
57
58 private static void add(float3 p, float3[] dest, ref int pcount)
59 {
60 dest[pcount++] = new float3(p);
61 Debug.Assert(pcount <= 4);
62 }
63
64 // assumes that the points are on opposite sides of the plane!
65 private static void intersect(float3 p1, float3 p2, float3 split, float4 plane)
66 {
67 float dp1 = DistToPt(p1, plane);
68 float[] dir = new float[3];
69
70 dir[0] = p2[0] - p1[0];
71 dir[1] = p2[1] - p1[1];
72 dir[2] = p2[2] - p1[2];
73
74 float dot1 = dir[0] * plane[0] + dir[1] * plane[1] + dir[2] * plane[2];
75 float dot2 = dp1 - plane[3];
76
77 float t = -(plane[3] + dot2) / dot1;
78
79 split.x = (dir[0] * t) + p1[0];
80 split.y = (dir[1] * t) + p1[1];
81 split.z = (dir[2] * t) + p1[2];
82 }
83
84 public static PlaneTriResult planeTriIntersection(float4 plane, FaceTri triangle, float epsilon, ref float3[] front, out int fcount, ref float3[] back, out int bcount)
85 {
86 fcount = 0;
87 bcount = 0;
88
89 // get the three vertices of the triangle.
90 float3 p1 = triangle.P1;
91 float3 p2 = triangle.P2;
92 float3 p3 = triangle.P3;
93
94 PlaneTriResult r1 = getSidePlane(p1, plane, epsilon); // compute the side of the plane each vertex is on
95 PlaneTriResult r2 = getSidePlane(p2, plane, epsilon);
96 PlaneTriResult r3 = getSidePlane(p3, plane, epsilon);
97
98 if (r1 == r2 && r1 == r3) // if all three vertices are on the same side of the plane.
99 {
100 if (r1 == PlaneTriResult.PTR_FRONT) // if all three are in front of the plane, then copy to the 'front' output triangle.
101 {
102 add(p1, front, ref fcount);
103 add(p2, front, ref fcount);
104 add(p3, front, ref fcount);
105 }
106 else
107 {
108 add(p1, back, ref bcount); // if all three are in 'back' then copy to the 'back' output triangle.
109 add(p2, back, ref bcount);
110 add(p3, back, ref bcount);
111 }
112 return r1; // if all three points are on the same side of the plane return result
113 }
114
115 // ok.. we need to split the triangle at the plane.
116
117 // First test ray segment P1 to P2
118 if (r1 == r2) // if these are both on the same side...
119 {
120 if (r1 == PlaneTriResult.PTR_FRONT)
121 {
122 add(p1, front, ref fcount);
123 add(p2, front, ref fcount);
124 }
125 else
126 {
127 add(p1, back, ref bcount);
128 add(p2, back, ref bcount);
129 }
130 }
131 else
132 {
133 float3 split = new float3();
134 intersect(p1, p2, split, plane);
135
136 if (r1 == PlaneTriResult.PTR_FRONT)
137 {
138
139 add(p1, front, ref fcount);
140 add(split, front, ref fcount);
141
142 add(split, back, ref bcount);
143 add(p2, back, ref bcount);
144
145 }
146 else
147 {
148 add(p1, back, ref bcount);
149 add(split, back, ref bcount);
150
151 add(split, front, ref fcount);
152 add(p2, front, ref fcount);
153 }
154
155 }
156
157 // Next test ray segment P2 to P3
158 if (r2 == r3) // if these are both on the same side...
159 {
160 if (r3 == PlaneTriResult.PTR_FRONT)
161 {
162 add(p3, front, ref fcount);
163 }
164 else
165 {
166 add(p3, back, ref bcount);
167 }
168 }
169 else
170 {
171 float3 split = new float3(); // split the point
172 intersect(p2, p3, split, plane);
173
174 if (r3 == PlaneTriResult.PTR_FRONT)
175 {
176 add(split, front, ref fcount);
177 add(split, back, ref bcount);
178
179 add(p3, front, ref fcount);
180 }
181 else
182 {
183 add(split, front, ref fcount);
184 add(split, back, ref bcount);
185
186 add(p3, back, ref bcount);
187 }
188 }
189
190 // Next test ray segment P3 to P1
191 if (r3 != r1) // if these are both on the same side...
192 {
193 float3 split = new float3(); // split the point
194 intersect(p3, p1, split, plane);
195
196 if (r1 == PlaneTriResult.PTR_FRONT)
197 {
198 add(split, front, ref fcount);
199 add(split, back, ref bcount);
200 }
201 else
202 {
203 add(split, front, ref fcount);
204 add(split, back, ref bcount);
205 }
206 }
207
208 return PlaneTriResult.PTR_SPLIT;
209 }
210 }
211}
diff --git a/OpenSim/Region/Physics/ConvexDecompositionDotNet/Properties/AssemblyInfo.cs b/OpenSim/Region/Physics/ConvexDecompositionDotNet/Properties/AssemblyInfo.cs
new file mode 100644
index 0000000..4285e8c
--- /dev/null
+++ b/OpenSim/Region/Physics/ConvexDecompositionDotNet/Properties/AssemblyInfo.cs
@@ -0,0 +1,36 @@
1using System.Reflection;
2using System.Runtime.CompilerServices;
3using System.Runtime.InteropServices;
4
5// General Information about an assembly is controlled through the following
6// set of attributes. Change these attribute values to modify the information
7// associated with an assembly.
8[assembly: AssemblyTitle("ConvexDecompositionDotNet")]
9[assembly: AssemblyDescription("")]
10[assembly: AssemblyConfiguration("")]
11[assembly: AssemblyCompany("Intel Corporation")]
12[assembly: AssemblyProduct("ConvexDecompositionDotNet")]
13[assembly: AssemblyCopyright("Copyright © Intel Corporation 2010")]
14[assembly: AssemblyTrademark("")]
15[assembly: AssemblyCulture("")]
16
17// Setting ComVisible to false makes the types in this assembly not visible
18// to COM components. If you need to access a type in this assembly from
19// COM, set the ComVisible attribute to true on that type.
20[assembly: ComVisible(false)]
21
22// The following GUID is for the ID of the typelib if this project is exposed to COM
23[assembly: Guid("2a1c9467-1a17-4c8d-bf9f-4b4d86dd0cbb")]
24
25// Version information for an assembly consists of the following four values:
26//
27// Major Version
28// Minor Version
29// Build Number
30// Revision
31//
32// You can specify all the values or you can default the Build and Revision Numbers
33// by using the '*' as shown below:
34// [assembly: AssemblyVersion("1.0.*")]
35[assembly: AssemblyVersion("1.0.0.0")]
36[assembly: AssemblyFileVersion("1.0.0.0")]
diff --git a/OpenSim/Region/Physics/ConvexDecompositionDotNet/Quaternion.cs b/OpenSim/Region/Physics/ConvexDecompositionDotNet/Quaternion.cs
new file mode 100644
index 0000000..0ba8f17
--- /dev/null
+++ b/OpenSim/Region/Physics/ConvexDecompositionDotNet/Quaternion.cs
@@ -0,0 +1,209 @@
1/* The MIT License
2 *
3 * Copyright (c) 2010 Intel Corporation.
4 * All rights reserved.
5 *
6 * Based on the convexdecomposition library from
7 * <http://codesuppository.googlecode.com> by John W. Ratcliff and Stan Melax.
8 *
9 * Permission is hereby granted, free of charge, to any person obtaining a copy
10 * of this software and associated documentation files (the "Software"), to deal
11 * in the Software without restriction, including without limitation the rights
12 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
13 * copies of the Software, and to permit persons to whom the Software is
14 * furnished to do so, subject to the following conditions:
15 *
16 * The above copyright notice and this permission notice shall be included in
17 * all copies or substantial portions of the Software.
18 *
19 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
20 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
21 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
22 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
23 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
24 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
25 * THE SOFTWARE.
26 */
27
28using System;
29
30namespace OpenSim.Region.Physics.ConvexDecompositionDotNet
31{
32 public class Quaternion : float4
33 {
34 public Quaternion()
35 {
36 x = y = z = 0.0f;
37 w = 1.0f;
38 }
39
40 public Quaternion(float3 v, float t)
41 {
42 v = float3.normalize(v);
43 w = (float)Math.Cos(t / 2.0f);
44 v = v * (float)Math.Sin(t / 2.0f);
45 x = v.x;
46 y = v.y;
47 z = v.z;
48 }
49
50 public Quaternion(float _x, float _y, float _z, float _w)
51 {
52 x = _x;
53 y = _y;
54 z = _z;
55 w = _w;
56 }
57
58 public float angle()
59 {
60 return (float)Math.Acos(w) * 2.0f;
61 }
62
63 public float3 axis()
64 {
65 float3 a = new float3(x, y, z);
66 if (Math.Abs(angle()) < 0.0000001f)
67 return new float3(1f, 0f, 0f);
68 return a * (1 / (float)Math.Sin(angle() / 2.0f));
69 }
70
71 public float3 xdir()
72 {
73 return new float3(1 - 2 * (y * y + z * z), 2 * (x * y + w * z), 2 * (x * z - w * y));
74 }
75
76 public float3 ydir()
77 {
78 return new float3(2 * (x * y - w * z), 1 - 2 * (x * x + z * z), 2 * (y * z + w * x));
79 }
80
81 public float3 zdir()
82 {
83 return new float3(2 * (x * z + w * y), 2 * (y * z - w * x), 1 - 2 * (x * x + y * y));
84 }
85
86 public float3x3 getmatrix()
87 {
88 return new float3x3(xdir(), ydir(), zdir());
89 }
90
91 public static implicit operator float3x3(Quaternion q)
92 {
93 return q.getmatrix();
94 }
95
96 public static Quaternion operator *(Quaternion a, Quaternion b)
97 {
98 Quaternion c = new Quaternion();
99 c.w = a.w * b.w - a.x * b.x - a.y * b.y - a.z * b.z;
100 c.x = a.w * b.x + a.x * b.w + a.y * b.z - a.z * b.y;
101 c.y = a.w * b.y - a.x * b.z + a.y * b.w + a.z * b.x;
102 c.z = a.w * b.z + a.x * b.y - a.y * b.x + a.z * b.w;
103 return c;
104 }
105
106 public static float3 operator *(Quaternion q, float3 v)
107 {
108 // The following is equivalent to:
109 //return (q.getmatrix() * v);
110 float qx2 = q.x * q.x;
111 float qy2 = q.y * q.y;
112 float qz2 = q.z * q.z;
113
114 float qxqy = q.x * q.y;
115 float qxqz = q.x * q.z;
116 float qxqw = q.x * q.w;
117 float qyqz = q.y * q.z;
118 float qyqw = q.y * q.w;
119 float qzqw = q.z * q.w;
120 return new float3((1 - 2 * (qy2 + qz2)) * v.x + (2 * (qxqy - qzqw)) * v.y + (2 * (qxqz + qyqw)) * v.z, (2 * (qxqy + qzqw)) * v.x + (1 - 2 * (qx2 + qz2)) * v.y + (2 * (qyqz - qxqw)) * v.z, (2 * (qxqz - qyqw)) * v.x + (2 * (qyqz + qxqw)) * v.y + (1 - 2 * (qx2 + qy2)) * v.z);
121 }
122
123 public static Quaternion operator +(Quaternion a, Quaternion b)
124 {
125 return new Quaternion(a.x + b.x, a.y + b.y, a.z + b.z, a.w + b.w);
126 }
127
128 public static Quaternion operator *(Quaternion a, float b)
129 {
130 return new Quaternion(a.x *b, a.y *b, a.z *b, a.w *b);
131 }
132
133 public static Quaternion normalize(Quaternion a)
134 {
135 float m = (float)Math.Sqrt(a.w * a.w + a.x * a.x + a.y * a.y + a.z * a.z);
136 if (m < 0.000000001f)
137 {
138 a.w = 1;
139 a.x = a.y = a.z = 0;
140 return a;
141 }
142 return a * (1f / m);
143 }
144
145 public static float dot(Quaternion a, Quaternion b)
146 {
147 return (a.w * b.w + a.x * b.x + a.y * b.y + a.z * b.z);
148 }
149
150 public static Quaternion slerp(Quaternion a, Quaternion b, float interp)
151 {
152 if (dot(a, b) < 0.0)
153 {
154 a.w = -a.w;
155 a.x = -a.x;
156 a.y = -a.y;
157 a.z = -a.z;
158 }
159 float d = dot(a, b);
160 if (d >= 1.0)
161 {
162 return a;
163 }
164 float theta = (float)Math.Acos(d);
165 if (theta == 0.0f)
166 {
167 return (a);
168 }
169 return a * ((float)Math.Sin(theta - interp * theta) / (float)Math.Sin(theta)) + b * ((float)Math.Sin(interp * theta) / (float)Math.Sin(theta));
170 }
171
172 public static Quaternion Interpolate(Quaternion q0, Quaternion q1, float alpha)
173 {
174 return slerp(q0, q1, alpha);
175 }
176
177 public static Quaternion Inverse(Quaternion q)
178 {
179 return new Quaternion(-q.x, -q.y, -q.z, q.w);
180 }
181
182 public static Quaternion YawPitchRoll(float yaw, float pitch, float roll)
183 {
184 roll *= (3.14159264f / 180.0f);
185 yaw *= (3.14159264f / 180.0f);
186 pitch *= (3.14159264f / 180.0f);
187 return new Quaternion(new float3(0.0f, 0.0f, 1.0f), yaw) * new Quaternion(new float3(1.0f, 0.0f, 0.0f), pitch) * new Quaternion(new float3(0.0f, 1.0f, 0.0f), roll);
188 }
189
190 public static float Yaw(Quaternion q)
191 {
192 float3 v = q.ydir();
193 return (v.y == 0.0 && v.x == 0.0) ? 0.0f : (float)Math.Atan2(-v.x, v.y) * (180.0f / 3.14159264f);
194 }
195
196 public static float Pitch(Quaternion q)
197 {
198 float3 v = q.ydir();
199 return (float)Math.Atan2(v.z, Math.Sqrt(v.x * v.x + v.y * v.y)) * (180.0f / 3.14159264f);
200 }
201
202 public static float Roll(Quaternion q)
203 {
204 q = new Quaternion(new float3(0.0f, 0.0f, 1.0f), -Yaw(q) * (3.14159264f / 180.0f)) * q;
205 q = new Quaternion(new float3(1.0f, 0.0f, 0.0f), -Pitch(q) * (3.14159264f / 180.0f)) * q;
206 return (float)Math.Atan2(-q.xdir().z, q.xdir().x) * (180.0f / 3.14159264f);
207 }
208 }
209}
diff --git a/OpenSim/Region/Physics/ConvexDecompositionDotNet/README.txt b/OpenSim/Region/Physics/ConvexDecompositionDotNet/README.txt
new file mode 100644
index 0000000..fc53ae7
--- /dev/null
+++ b/OpenSim/Region/Physics/ConvexDecompositionDotNet/README.txt
@@ -0,0 +1,7 @@
1ConvexDecompositionDotNet
2=========================
3
4A C# port of the ConvexDecomposition library by John W. Ratcliff and Stan Melax.
5The original C++ version is available at <http://codesuppository.googlecode.com/>.
6See the blog post at <http://codesuppository.blogspot.com/2006/08/approximate-convexdecomposition.html>
7for a thorough explanation of generating convex hulls from concave meshes.
diff --git a/OpenSim/Region/Physics/ConvexDecompositionDotNet/SplitPlane.cs b/OpenSim/Region/Physics/ConvexDecompositionDotNet/SplitPlane.cs
new file mode 100644
index 0000000..9f06a9a
--- /dev/null
+++ b/OpenSim/Region/Physics/ConvexDecompositionDotNet/SplitPlane.cs
@@ -0,0 +1,265 @@
1/* The MIT License
2 *
3 * Copyright (c) 2010 Intel Corporation.
4 * All rights reserved.
5 *
6 * Based on the convexdecomposition library from
7 * <http://codesuppository.googlecode.com> by John W. Ratcliff and Stan Melax.
8 *
9 * Permission is hereby granted, free of charge, to any person obtaining a copy
10 * of this software and associated documentation files (the "Software"), to deal
11 * in the Software without restriction, including without limitation the rights
12 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
13 * copies of the Software, and to permit persons to whom the Software is
14 * furnished to do so, subject to the following conditions:
15 *
16 * The above copyright notice and this permission notice shall be included in
17 * all copies or substantial portions of the Software.
18 *
19 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
20 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
21 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
22 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
23 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
24 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
25 * THE SOFTWARE.
26 */
27
28using System;
29using System.Collections.Generic;
30
31namespace OpenSim.Region.Physics.ConvexDecompositionDotNet
32{
33 public class Rect3d
34 {
35 public float[] mMin = new float[3];
36 public float[] mMax = new float[3];
37
38 public Rect3d()
39 {
40 }
41
42 public Rect3d(float[] bmin, float[] bmax)
43 {
44 mMin[0] = bmin[0];
45 mMin[1] = bmin[1];
46 mMin[2] = bmin[2];
47
48 mMax[0] = bmax[0];
49 mMax[1] = bmax[1];
50 mMax[2] = bmax[2];
51 }
52
53 public void SetMin(float[] bmin)
54 {
55 mMin[0] = bmin[0];
56 mMin[1] = bmin[1];
57 mMin[2] = bmin[2];
58 }
59
60 public void SetMax(float[] bmax)
61 {
62 mMax[0] = bmax[0];
63 mMax[1] = bmax[1];
64 mMax[2] = bmax[2];
65 }
66
67 public void SetMin(float x, float y, float z)
68 {
69 mMin[0] = x;
70 mMin[1] = y;
71 mMin[2] = z;
72 }
73
74 public void SetMax(float x, float y, float z)
75 {
76 mMax[0] = x;
77 mMax[1] = y;
78 mMax[2] = z;
79 }
80 }
81
82 public static class SplitPlane
83 {
84 public static bool computeSplitPlane(List<float3> vertices, List<int> indices, ref float4 plane)
85 {
86 float[] bmin = { Single.MaxValue, Single.MaxValue, Single.MaxValue };
87 float[] bmax = { Single.MinValue, Single.MinValue, Single.MinValue };
88
89 for (int i = 0; i < vertices.Count; i++)
90 {
91 float3 p = vertices[i];
92
93 if (p[0] < bmin[0])
94 bmin[0] = p[0];
95 if (p[1] < bmin[1])
96 bmin[1] = p[1];
97 if (p[2] < bmin[2])
98 bmin[2] = p[2];
99
100 if (p[0] > bmax[0])
101 bmax[0] = p[0];
102 if (p[1] > bmax[1])
103 bmax[1] = p[1];
104 if (p[2] > bmax[2])
105 bmax[2] = p[2];
106 }
107
108 float dx = bmax[0] - bmin[0];
109 float dy = bmax[1] - bmin[1];
110 float dz = bmax[2] - bmin[2];
111
112 float laxis = dx;
113
114 int axis = 0;
115
116 if (dy > dx)
117 {
118 axis = 1;
119 laxis = dy;
120 }
121
122 if (dz > dx && dz > dy)
123 {
124 axis = 2;
125 laxis = dz;
126 }
127
128 float[] p1 = new float[3];
129 float[] p2 = new float[3];
130 float[] p3 = new float[3];
131
132 p3[0] = p2[0] = p1[0] = bmin[0] + dx * 0.5f;
133 p3[1] = p2[1] = p1[1] = bmin[1] + dy * 0.5f;
134 p3[2] = p2[2] = p1[2] = bmin[2] + dz * 0.5f;
135
136 Rect3d b = new Rect3d(bmin, bmax);
137
138 Rect3d b1 = new Rect3d();
139 Rect3d b2 = new Rect3d();
140
141 splitRect(axis, b, b1, b2, p1);
142
143 switch (axis)
144 {
145 case 0:
146 p2[1] = bmin[1];
147 p2[2] = bmin[2];
148
149 if (dz > dy)
150 {
151 p3[1] = bmax[1];
152 p3[2] = bmin[2];
153 }
154 else
155 {
156 p3[1] = bmin[1];
157 p3[2] = bmax[2];
158 }
159
160 break;
161 case 1:
162 p2[0] = bmin[0];
163 p2[2] = bmin[2];
164
165 if (dx > dz)
166 {
167 p3[0] = bmax[0];
168 p3[2] = bmin[2];
169 }
170 else
171 {
172 p3[0] = bmin[0];
173 p3[2] = bmax[2];
174 }
175
176 break;
177 case 2:
178 p2[0] = bmin[0];
179 p2[1] = bmin[1];
180
181 if (dx > dy)
182 {
183 p3[0] = bmax[0];
184 p3[1] = bmin[1];
185 }
186 else
187 {
188 p3[0] = bmin[0];
189 p3[1] = bmax[1];
190 }
191
192 break;
193 }
194
195 computePlane(p1, p2, p3, plane);
196
197 return true;
198 }
199
200 internal static void computePlane(float[] A, float[] B, float[] C, float4 plane)
201 {
202 float vx = (B[0] - C[0]);
203 float vy = (B[1] - C[1]);
204 float vz = (B[2] - C[2]);
205
206 float wx = (A[0] - B[0]);
207 float wy = (A[1] - B[1]);
208 float wz = (A[2] - B[2]);
209
210 float vw_x = vy * wz - vz * wy;
211 float vw_y = vz * wx - vx * wz;
212 float vw_z = vx * wy - vy * wx;
213
214 float mag = (float)Math.Sqrt((vw_x * vw_x) + (vw_y * vw_y) + (vw_z * vw_z));
215
216 if (mag < 0.000001f)
217 {
218 mag = 0;
219 }
220 else
221 {
222 mag = 1.0f / mag;
223 }
224
225 float x = vw_x * mag;
226 float y = vw_y * mag;
227 float z = vw_z * mag;
228
229 float D = 0.0f - ((x * A[0]) + (y * A[1]) + (z * A[2]));
230
231 plane.x = x;
232 plane.y = y;
233 plane.z = z;
234 plane.w = D;
235 }
236
237 public static void splitRect(int axis, Rect3d source, Rect3d b1, Rect3d b2, float[] midpoint)
238 {
239 switch (axis)
240 {
241 case 0:
242 b1.SetMin(source.mMin);
243 b1.SetMax(midpoint[0], source.mMax[1], source.mMax[2]);
244
245 b2.SetMin(midpoint[0], source.mMin[1], source.mMin[2]);
246 b2.SetMax(source.mMax);
247 break;
248 case 1:
249 b1.SetMin(source.mMin);
250 b1.SetMax(source.mMax[0], midpoint[1], source.mMax[2]);
251
252 b2.SetMin(source.mMin[0], midpoint[1], source.mMin[2]);
253 b2.SetMax(source.mMax);
254 break;
255 case 2:
256 b1.SetMin(source.mMin);
257 b1.SetMax(source.mMax[0], source.mMax[1], midpoint[2]);
258
259 b2.SetMin(source.mMin[0], source.mMin[1], midpoint[2]);
260 b2.SetMax(source.mMax);
261 break;
262 }
263 }
264 }
265}
diff --git a/OpenSim/Region/Physics/ConvexDecompositionDotNet/VertexLookup.cs b/OpenSim/Region/Physics/ConvexDecompositionDotNet/VertexLookup.cs
new file mode 100644
index 0000000..6f17c9f
--- /dev/null
+++ b/OpenSim/Region/Physics/ConvexDecompositionDotNet/VertexLookup.cs
@@ -0,0 +1,70 @@
1/* The MIT License
2 *
3 * Copyright (c) 2010 Intel Corporation.
4 * All rights reserved.
5 *
6 * Based on the convexdecomposition library from
7 * <http://codesuppository.googlecode.com> by John W. Ratcliff and Stan Melax.
8 *
9 * Permission is hereby granted, free of charge, to any person obtaining a copy
10 * of this software and associated documentation files (the "Software"), to deal
11 * in the Software without restriction, including without limitation the rights
12 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
13 * copies of the Software, and to permit persons to whom the Software is
14 * furnished to do so, subject to the following conditions:
15 *
16 * The above copyright notice and this permission notice shall be included in
17 * all copies or substantial portions of the Software.
18 *
19 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
20 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
21 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
22 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
23 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
24 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
25 * THE SOFTWARE.
26 */
27
28using System;
29using System.Collections.Generic;
30
31namespace OpenSim.Region.Physics.ConvexDecompositionDotNet
32{
33 public class VertexPool
34 {
35 private List<float3> mVertices = new List<float3>();
36 private Dictionary<float3, int> mIndices = new Dictionary<float3, int>();
37
38 public int getIndex(float3 vtx)
39 {
40 int idx;
41 if (mIndices.TryGetValue(vtx, out idx))
42 return idx;
43
44 idx = mVertices.Count;
45 mVertices.Add(vtx);
46 mIndices.Add(vtx, idx);
47 return idx;
48 }
49
50 public float3 Get(int idx)
51 {
52 return mVertices[idx];
53 }
54
55 public int GetSize()
56 {
57 return mVertices.Count;
58 }
59
60 public List<float3> GetVertices()
61 {
62 return mVertices;
63 }
64
65 public void Clear()
66 {
67 mVertices.Clear();
68 }
69 }
70}
diff --git a/OpenSim/Region/Physics/ConvexDecompositionDotNet/float2.cs b/OpenSim/Region/Physics/ConvexDecompositionDotNet/float2.cs
new file mode 100644
index 0000000..ce88fc8
--- /dev/null
+++ b/OpenSim/Region/Physics/ConvexDecompositionDotNet/float2.cs
@@ -0,0 +1,70 @@
1/* The MIT License
2 *
3 * Copyright (c) 2010 Intel Corporation.
4 * All rights reserved.
5 *
6 * Based on the convexdecomposition library from
7 * <http://codesuppository.googlecode.com> by John W. Ratcliff and Stan Melax.
8 *
9 * Permission is hereby granted, free of charge, to any person obtaining a copy
10 * of this software and associated documentation files (the "Software"), to deal
11 * in the Software without restriction, including without limitation the rights
12 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
13 * copies of the Software, and to permit persons to whom the Software is
14 * furnished to do so, subject to the following conditions:
15 *
16 * The above copyright notice and this permission notice shall be included in
17 * all copies or substantial portions of the Software.
18 *
19 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
20 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
21 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
22 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
23 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
24 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
25 * THE SOFTWARE.
26 */
27
28using System;
29
30namespace OpenSim.Region.Physics.ConvexDecompositionDotNet
31{
32 public class float2
33 {
34 public float x;
35 public float y;
36
37 public float2()
38 {
39 }
40
41 public float2(float _x, float _y)
42 {
43 x = _x;
44 y = _y;
45 }
46
47 public float this[int i]
48 {
49 get
50 {
51 switch (i)
52 {
53 case 0: return x;
54 case 1: return y;
55 }
56 throw new ArgumentOutOfRangeException();
57 }
58 }
59
60 public static float2 operator -(float2 a, float2 b)
61 {
62 return new float2(a.x - b.x, a.y - b.y);
63 }
64
65 public static float2 operator +(float2 a, float2 b)
66 {
67 return new float2(a.x + b.x, a.y + b.y);
68 }
69 }
70}
diff --git a/OpenSim/Region/Physics/ConvexDecompositionDotNet/float3.cs b/OpenSim/Region/Physics/ConvexDecompositionDotNet/float3.cs
new file mode 100644
index 0000000..4389114
--- /dev/null
+++ b/OpenSim/Region/Physics/ConvexDecompositionDotNet/float3.cs
@@ -0,0 +1,444 @@
1/* The MIT License
2 *
3 * Copyright (c) 2010 Intel Corporation.
4 * All rights reserved.
5 *
6 * Based on the convexdecomposition library from
7 * <http://codesuppository.googlecode.com> by John W. Ratcliff and Stan Melax.
8 *
9 * Permission is hereby granted, free of charge, to any person obtaining a copy
10 * of this software and associated documentation files (the "Software"), to deal
11 * in the Software without restriction, including without limitation the rights
12 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
13 * copies of the Software, and to permit persons to whom the Software is
14 * furnished to do so, subject to the following conditions:
15 *
16 * The above copyright notice and this permission notice shall be included in
17 * all copies or substantial portions of the Software.
18 *
19 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
20 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
21 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
22 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
23 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
24 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
25 * THE SOFTWARE.
26 */
27
28using System;
29
30namespace OpenSim.Region.Physics.ConvexDecompositionDotNet
31{
32 public class float3 : IEquatable<float3>
33 {
34 public float x;
35 public float y;
36 public float z;
37
38 public float3()
39 {
40 x = 0;
41 y = 0;
42 z = 0;
43 }
44
45 public float3(float _x, float _y, float _z)
46 {
47 x = _x;
48 y = _y;
49 z = _z;
50 }
51
52 public float3(float3 f)
53 {
54 x = f.x;
55 y = f.y;
56 z = f.z;
57 }
58
59 public float this[int i]
60 {
61 get
62 {
63 switch (i)
64 {
65 case 0: return x;
66 case 1: return y;
67 case 2: return z;
68 }
69 throw new ArgumentOutOfRangeException();
70 }
71 }
72
73 public float Distance(float3 a)
74 {
75 float3 d = new float3(a.x - x, a.y - y, a.z - z);
76 return d.Length();
77 }
78
79 public float Distance2(float3 a)
80 {
81 float dx = a.x - x;
82 float dy = a.y - y;
83 float dz = a.z - z;
84 return dx * dx + dy * dy + dz * dz;
85 }
86
87 public float Length()
88 {
89 return (float)Math.Sqrt(x * x + y * y + z * z);
90 }
91
92 public float Area(float3 p1, float3 p2)
93 {
94 float A = Partial(p1);
95 A += p1.Partial(p2);
96 A += p2.Partial(this);
97 return A * 0.5f;
98 }
99
100 public float Partial(float3 p)
101 {
102 return (x * p.y) - (p.x * y);
103 }
104
105 // Given a point and a line (defined by two points), compute the closest point
106 // in the line. (The line is treated as infinitely long.)
107 public void NearestPointInLine(float3 point, float3 line0, float3 line1)
108 {
109 float3 nearestPoint = new float3();
110 float3 lineDelta = line1 - line0;
111
112 // Handle degenerate lines
113 if (lineDelta == float3.Zero)
114 {
115 nearestPoint = line0;
116 }
117 else
118 {
119 float delta = float3.dot(point - line0, lineDelta) / float3.dot(lineDelta, lineDelta);
120 nearestPoint = line0 + lineDelta * delta;
121 }
122
123 this.x = nearestPoint.x;
124 this.y = nearestPoint.y;
125 this.z = nearestPoint.z;
126 }
127
128 // Given a point and a line segment (defined by two points), compute the closest point
129 // in the line. Cap the point at the endpoints of the line segment.
130 public void NearestPointInLineSegment(float3 point, float3 line0, float3 line1)
131 {
132 float3 nearestPoint = new float3();
133 float3 lineDelta = line1 - line0;
134
135 // Handle degenerate lines
136 if (lineDelta == Zero)
137 {
138 nearestPoint = line0;
139 }
140 else
141 {
142 float delta = float3.dot(point - line0, lineDelta) / float3.dot(lineDelta, lineDelta);
143
144 // Clamp the point to conform to the segment's endpoints
145 if (delta < 0)
146 delta = 0;
147 else if (delta > 1)
148 delta = 1;
149
150 nearestPoint = line0 + lineDelta * delta;
151 }
152
153 this.x = nearestPoint.x;
154 this.y = nearestPoint.y;
155 this.z = nearestPoint.z;
156 }
157
158 // Given a point and a triangle (defined by three points), compute the closest point
159 // in the triangle. Clamp the point so it's confined to the area of the triangle.
160 public void NearestPointInTriangle(float3 point, float3 triangle0, float3 triangle1, float3 triangle2)
161 {
162 float3 nearestPoint = new float3();
163
164 float3 lineDelta0 = triangle1 - triangle0;
165 float3 lineDelta1 = triangle2 - triangle0;
166
167 // Handle degenerate triangles
168 if ((lineDelta0 == Zero) || (lineDelta1 == Zero))
169 {
170 nearestPoint.NearestPointInLineSegment(point, triangle1, triangle2);
171 }
172 else if (lineDelta0 == lineDelta1)
173 {
174 nearestPoint.NearestPointInLineSegment(point, triangle0, triangle1);
175 }
176 else
177 {
178 float3[] axis = new float3[3] { new float3(), new float3(), new float3() };
179 axis[0].NearestPointInLine(triangle0, triangle1, triangle2);
180 axis[1].NearestPointInLine(triangle1, triangle0, triangle2);
181 axis[2].NearestPointInLine(triangle2, triangle0, triangle1);
182
183 float3 axisDot = new float3();
184 axisDot.x = dot(triangle0 - axis[0], point - axis[0]);
185 axisDot.y = dot(triangle1 - axis[1], point - axis[1]);
186 axisDot.z = dot(triangle2 - axis[2], point - axis[2]);
187
188 bool bForce = true;
189 float bestMagnitude2 = 0;
190 float closeMagnitude2;
191 float3 closePoint = new float3();
192
193 if (axisDot.x < 0f)
194 {
195 closePoint.NearestPointInLineSegment(point, triangle1, triangle2);
196 closeMagnitude2 = point.Distance2(closePoint);
197 if (bForce || (bestMagnitude2 > closeMagnitude2))
198 {
199 bForce = false;
200 bestMagnitude2 = closeMagnitude2;
201 nearestPoint = closePoint;
202 }
203 }
204 if (axisDot.y < 0f)
205 {
206 closePoint.NearestPointInLineSegment(point, triangle0, triangle2);
207 closeMagnitude2 = point.Distance2(closePoint);
208 if (bForce || (bestMagnitude2 > closeMagnitude2))
209 {
210 bForce = false;
211 bestMagnitude2 = closeMagnitude2;
212 nearestPoint = closePoint;
213 }
214 }
215 if (axisDot.z < 0f)
216 {
217 closePoint.NearestPointInLineSegment(point, triangle0, triangle1);
218 closeMagnitude2 = point.Distance2(closePoint);
219 if (bForce || (bestMagnitude2 > closeMagnitude2))
220 {
221 bForce = false;
222 bestMagnitude2 = closeMagnitude2;
223 nearestPoint = closePoint;
224 }
225 }
226
227 // If bForce is true at this point, it means the nearest point lies
228 // inside the triangle; use the nearest-point-on-a-plane equation
229 if (bForce)
230 {
231 float3 normal;
232
233 // Get the normal of the polygon (doesn't have to be a unit vector)
234 normal = float3.cross(lineDelta0, lineDelta1);
235
236 float3 pointDelta = point - triangle0;
237 float delta = float3.dot(normal, pointDelta) / float3.dot(normal, normal);
238
239 nearestPoint = point - normal * delta;
240 }
241 }
242
243 this.x = nearestPoint.x;
244 this.y = nearestPoint.y;
245 this.z = nearestPoint.z;
246 }
247
248 public static float3 operator +(float3 a, float3 b)
249 {
250 return new float3(a.x + b.x, a.y + b.y, a.z + b.z);
251 }
252
253 public static float3 operator -(float3 a, float3 b)
254 {
255 return new float3(a.x - b.x, a.y - b.y, a.z - b.z);
256 }
257
258 public static float3 operator -(float3 a, float s)
259 {
260 return new float3(a.x - s, a.y - s, a.z - s);
261 }
262
263 public static float3 operator -(float3 v)
264 {
265 return new float3(-v.x, -v.y, -v.z);
266 }
267
268 public static float3 operator *(float3 v, float s)
269 {
270 return new float3(v.x * s, v.y * s, v.z * s);
271 }
272
273 public static float3 operator *(float s, float3 v)
274 {
275 return new float3(v.x * s, v.y * s, v.z * s);
276 }
277
278 public static float3 operator *(float3 v, float3x3 m)
279 {
280 return new float3((m.x.x * v.x + m.y.x * v.y + m.z.x * v.z), (m.x.y * v.x + m.y.y * v.y + m.z.y * v.z), (m.x.z * v.x + m.y.z * v.y + m.z.z * v.z));
281 }
282
283 public static float3 operator *(float3x3 m, float3 v)
284 {
285 return new float3(dot(m.x, v), dot(m.y, v), dot(m.z, v));
286 }
287
288 public static float3 operator /(float3 v, float s)
289 {
290 float sinv = 1.0f / s;
291 return new float3(v.x * sinv, v.y * sinv, v.z * sinv);
292 }
293
294 public bool Equals(float3 other)
295 {
296 return this == other;
297 }
298
299 public override bool Equals(object obj)
300 {
301 float3 f = obj as float3;
302 if (f == null)
303 return false;
304
305 return this == f;
306 }
307
308 public override int GetHashCode()
309 {
310 return x.GetHashCode() ^ y.GetHashCode() ^ z.GetHashCode();
311 }
312
313 public static bool operator ==(float3 a, float3 b)
314 {
315 // If both are null, or both are same instance, return true.
316 if (System.Object.ReferenceEquals(a, b))
317 return true;
318 // If one is null, but not both, return false.
319 if (((object)a == null) || ((object)b == null))
320 return false;
321
322 return (a.x == b.x && a.y == b.y && a.z == b.z);
323 }
324
325 public static bool operator !=(float3 a, float3 b)
326 {
327 return (a.x != b.x || a.y != b.y || a.z != b.z);
328 }
329
330 public static float dot(float3 a, float3 b)
331 {
332 return a.x * b.x + a.y * b.y + a.z * b.z;
333 }
334
335 public static float3 cmul(float3 v1, float3 v2)
336 {
337 return new float3(v1.x * v2.x, v1.y * v2.y, v1.z * v2.z);
338 }
339
340 public static float3 cross(float3 a, float3 b)
341 {
342 return new float3(a.y * b.z - a.z * b.y, a.z * b.x - a.x * b.z, a.x * b.y - a.y * b.x);
343 }
344
345 public static float3 Interpolate(float3 v0, float3 v1, float alpha)
346 {
347 return v0 * (1 - alpha) + v1 * alpha;
348 }
349
350 public static float3 Round(float3 a, int digits)
351 {
352 return new float3((float)Math.Round(a.x, digits), (float)Math.Round(a.y, digits), (float)Math.Round(a.z, digits));
353 }
354
355 public static float3 VectorMax(float3 a, float3 b)
356 {
357 return new float3(Math.Max(a.x, b.x), Math.Max(a.y, b.y), Math.Max(a.z, b.z));
358 }
359
360 public static float3 VectorMin(float3 a, float3 b)
361 {
362 return new float3(Math.Min(a.x, b.x), Math.Min(a.y, b.y), Math.Min(a.z, b.z));
363 }
364
365 public static float3 vabs(float3 v)
366 {
367 return new float3(Math.Abs(v.x), Math.Abs(v.y), Math.Abs(v.z));
368 }
369
370 public static float magnitude(float3 v)
371 {
372 return (float)Math.Sqrt(v.x * v.x + v.y * v.y + v.z * v.z);
373 }
374
375 public static float3 normalize(float3 v)
376 {
377 float d = magnitude(v);
378 if (d == 0)
379 d = 0.1f;
380 d = 1 / d;
381 return new float3(v.x * d, v.y * d, v.z * d);
382 }
383
384 public static float3 safenormalize(float3 v)
385 {
386 if (magnitude(v) <= 0.0f)
387 return new float3(1, 0, 0);
388 else
389 return normalize(v);
390 }
391
392 public static float Yaw(float3 v)
393 {
394 return (v.y == 0.0 && v.x == 0.0) ? 0.0f : (float)Math.Atan2(-v.x, v.y) * (180.0f / 3.14159264f);
395 }
396
397 public static float Pitch(float3 v)
398 {
399 return (float)Math.Atan2(v.z, Math.Sqrt(v.x * v.x + v.y * v.y)) * (180.0f / 3.14159264f);
400 }
401
402 public float ComputePlane(float3 A, float3 B, float3 C)
403 {
404 float vx, vy, vz, wx, wy, wz, vw_x, vw_y, vw_z, mag;
405
406 vx = (B.x - C.x);
407 vy = (B.y - C.y);
408 vz = (B.z - C.z);
409
410 wx = (A.x - B.x);
411 wy = (A.y - B.y);
412 wz = (A.z - B.z);
413
414 vw_x = vy * wz - vz * wy;
415 vw_y = vz * wx - vx * wz;
416 vw_z = vx * wy - vy * wx;
417
418 mag = (float)Math.Sqrt((vw_x * vw_x) + (vw_y * vw_y) + (vw_z * vw_z));
419
420 if (mag < 0.000001f)
421 {
422 mag = 0;
423 }
424 else
425 {
426 mag = 1.0f / mag;
427 }
428
429 x = vw_x * mag;
430 y = vw_y * mag;
431 z = vw_z * mag;
432
433 float D = 0.0f - ((x * A.x) + (y * A.y) + (z * A.z));
434 return D;
435 }
436
437 public override string ToString()
438 {
439 return String.Format("<{0}, {1}, {2}>", x, y, z);
440 }
441
442 public static readonly float3 Zero = new float3();
443 }
444}
diff --git a/OpenSim/Region/Physics/ConvexDecompositionDotNet/float3x3.cs b/OpenSim/Region/Physics/ConvexDecompositionDotNet/float3x3.cs
new file mode 100644
index 0000000..76cf063
--- /dev/null
+++ b/OpenSim/Region/Physics/ConvexDecompositionDotNet/float3x3.cs
@@ -0,0 +1,195 @@
1/* The MIT License
2 *
3 * Copyright (c) 2010 Intel Corporation.
4 * All rights reserved.
5 *
6 * Based on the convexdecomposition library from
7 * <http://codesuppository.googlecode.com> by John W. Ratcliff and Stan Melax.
8 *
9 * Permission is hereby granted, free of charge, to any person obtaining a copy
10 * of this software and associated documentation files (the "Software"), to deal
11 * in the Software without restriction, including without limitation the rights
12 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
13 * copies of the Software, and to permit persons to whom the Software is
14 * furnished to do so, subject to the following conditions:
15 *
16 * The above copyright notice and this permission notice shall be included in
17 * all copies or substantial portions of the Software.
18 *
19 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
20 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
21 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
22 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
23 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
24 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
25 * THE SOFTWARE.
26 */
27
28using System;
29using System.Collections.Generic;
30using System.Diagnostics;
31
32namespace OpenSim.Region.Physics.ConvexDecompositionDotNet
33{
34 public class float3x3
35 {
36 public float3 x = new float3();
37 public float3 y = new float3();
38 public float3 z = new float3();
39
40 public float3x3()
41 {
42 }
43
44 public float3x3(float xx, float xy, float xz, float yx, float yy, float yz, float zx, float zy, float zz)
45 {
46 x = new float3(xx, xy, xz);
47 y = new float3(yx, yy, yz);
48 z = new float3(zx, zy, zz);
49 }
50
51 public float3x3(float3 _x, float3 _y, float3 _z)
52 {
53 x = new float3(_x);
54 y = new float3(_y);
55 z = new float3(_z);
56 }
57
58 public float3 this[int i]
59 {
60 get
61 {
62 switch (i)
63 {
64 case 0: return x;
65 case 1: return y;
66 case 2: return z;
67 }
68 throw new ArgumentOutOfRangeException();
69 }
70 }
71
72 public float this[int i, int j]
73 {
74 get
75 {
76 switch (i)
77 {
78 case 0:
79 switch (j)
80 {
81 case 0: return x.x;
82 case 1: return x.y;
83 case 2: return x.z;
84 }
85 break;
86 case 1:
87 switch (j)
88 {
89 case 0: return y.x;
90 case 1: return y.y;
91 case 2: return y.z;
92 }
93 break;
94 case 2:
95 switch (j)
96 {
97 case 0: return z.x;
98 case 1: return z.y;
99 case 2: return z.z;
100 }
101 break;
102 }
103 throw new ArgumentOutOfRangeException();
104 }
105 set
106 {
107 switch (i)
108 {
109 case 0:
110 switch (j)
111 {
112 case 0: x.x = value; return;
113 case 1: x.y = value; return;
114 case 2: x.z = value; return;
115 }
116 break;
117 case 1:
118 switch (j)
119 {
120 case 0: y.x = value; return;
121 case 1: y.y = value; return;
122 case 2: y.z = value; return;
123 }
124 break;
125 case 2:
126 switch (j)
127 {
128 case 0: z.x = value; return;
129 case 1: z.y = value; return;
130 case 2: z.z = value; return;
131 }
132 break;
133 }
134 throw new ArgumentOutOfRangeException();
135 }
136 }
137
138 public static float3x3 Transpose(float3x3 m)
139 {
140 return new float3x3(new float3(m.x.x, m.y.x, m.z.x), new float3(m.x.y, m.y.y, m.z.y), new float3(m.x.z, m.y.z, m.z.z));
141 }
142
143 public static float3x3 operator *(float3x3 a, float3x3 b)
144 {
145 return new float3x3(a.x * b, a.y * b, a.z * b);
146 }
147
148 public static float3x3 operator *(float3x3 a, float s)
149 {
150 return new float3x3(a.x * s, a.y * s, a.z * s);
151 }
152
153 public static float3x3 operator /(float3x3 a, float s)
154 {
155 float t = 1f / s;
156 return new float3x3(a.x * t, a.y * t, a.z * t);
157 }
158
159 public static float3x3 operator +(float3x3 a, float3x3 b)
160 {
161 return new float3x3(a.x + b.x, a.y + b.y, a.z + b.z);
162 }
163
164 public static float3x3 operator -(float3x3 a, float3x3 b)
165 {
166 return new float3x3(a.x - b.x, a.y - b.y, a.z - b.z);
167 }
168
169 public static float Determinant(float3x3 m)
170 {
171 return m.x.x * m.y.y * m.z.z + m.y.x * m.z.y * m.x.z + m.z.x * m.x.y * m.y.z - m.x.x * m.z.y * m.y.z - m.y.x * m.x.y * m.z.z - m.z.x * m.y.y * m.x.z;
172 }
173
174 public static float3x3 Inverse(float3x3 a)
175 {
176 float3x3 b = new float3x3();
177 float d = Determinant(a);
178 Debug.Assert(d != 0);
179 for (int i = 0; i < 3; i++)
180 {
181 for (int j = 0; j < 3; j++)
182 {
183 int i1 = (i + 1) % 3;
184 int i2 = (i + 2) % 3;
185 int j1 = (j + 1) % 3;
186 int j2 = (j + 2) % 3;
187
188 // reverse indexs i&j to take transpose
189 b[i, j] = (a[i1][j1] * a[i2][j2] - a[i1][j2] * a[i2][j1]) / d;
190 }
191 }
192 return b;
193 }
194 }
195}
diff --git a/OpenSim/Region/Physics/ConvexDecompositionDotNet/float4.cs b/OpenSim/Region/Physics/ConvexDecompositionDotNet/float4.cs
new file mode 100644
index 0000000..fa60876
--- /dev/null
+++ b/OpenSim/Region/Physics/ConvexDecompositionDotNet/float4.cs
@@ -0,0 +1,170 @@
1/* The MIT License
2 *
3 * Copyright (c) 2010 Intel Corporation.
4 * All rights reserved.
5 *
6 * Based on the convexdecomposition library from
7 * <http://codesuppository.googlecode.com> by John W. Ratcliff and Stan Melax.
8 *
9 * Permission is hereby granted, free of charge, to any person obtaining a copy
10 * of this software and associated documentation files (the "Software"), to deal
11 * in the Software without restriction, including without limitation the rights
12 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
13 * copies of the Software, and to permit persons to whom the Software is
14 * furnished to do so, subject to the following conditions:
15 *
16 * The above copyright notice and this permission notice shall be included in
17 * all copies or substantial portions of the Software.
18 *
19 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
20 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
21 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
22 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
23 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
24 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
25 * THE SOFTWARE.
26 */
27
28using System;
29
30namespace OpenSim.Region.Physics.ConvexDecompositionDotNet
31{
32 public class float4
33 {
34 public float x;
35 public float y;
36 public float z;
37 public float w;
38
39 public float4()
40 {
41 x = 0;
42 y = 0;
43 z = 0;
44 w = 0;
45 }
46
47 public float4(float _x, float _y, float _z, float _w)
48 {
49 x = _x;
50 y = _y;
51 z = _z;
52 w = _w;
53 }
54
55 public float4(float3 v, float _w)
56 {
57 x = v.x;
58 y = v.y;
59 z = v.z;
60 w = _w;
61 }
62
63 public float4(float4 f)
64 {
65 x = f.x;
66 y = f.y;
67 z = f.z;
68 w = f.w;
69 }
70
71 public float this[int i]
72 {
73 get
74 {
75 switch (i)
76 {
77 case 0: return x;
78 case 1: return y;
79 case 2: return z;
80 case 3: return w;
81 }
82 throw new ArgumentOutOfRangeException();
83 }
84 }
85
86 public float3 xyz()
87 {
88 return new float3(x, y, z);
89 }
90
91 public void setxyz(float3 xyz)
92 {
93 x = xyz.x;
94 y = xyz.y;
95 z = xyz.z;
96 }
97
98 public override int GetHashCode()
99 {
100 return x.GetHashCode() ^ y.GetHashCode() ^ z.GetHashCode() ^ w.GetHashCode();
101 }
102
103 public override bool Equals(object obj)
104 {
105 float4 f = obj as float4;
106 if (f == null)
107 return false;
108
109 return this == f;
110 }
111
112 public static float4 Homogenize(float3 v3)
113 {
114 return Homogenize(v3, 1.0f);
115 }
116
117 //C++ TO C# CONVERTER NOTE: C# does not allow default values for parameters. Overloaded methods are inserted above.
118 //ORIGINAL LINE: float4 Homogenize(const float3 &v3, const float &w =1.0f)
119 public static float4 Homogenize(float3 v3, float w)
120 {
121 return new float4(v3.x, v3.y, v3.z, w);
122 }
123
124 public static float4 cmul(float4 a, float4 b)
125 {
126 return new float4(a.x * b.x, a.y * b.y, a.z * b.z, a.w * b.w);
127 }
128
129 public static float4 operator +(float4 a, float4 b)
130 {
131 return new float4(a.x + b.x, a.y + b.y, a.z + b.z, a.w + b.w);
132 }
133 public static float4 operator -(float4 a, float4 b)
134 {
135 return new float4(a.x - b.x, a.y - b.y, a.z - b.z, a.w - b.w);
136 }
137
138 public static float4 operator *(float4 v, float4x4 m)
139 {
140 return v.x * m.x + v.y * m.y + v.z * m.z + v.w * m.w; // yes this actually works
141 }
142
143 public static bool operator ==(float4 a, float4 b)
144 {
145 // If both are null, or both are same instance, return true.
146 if (System.Object.ReferenceEquals(a, b))
147 return true;
148 // If one is null, but not both, return false.
149 if (((object)a == null) || ((object)b == null))
150 return false;
151
152 return (a.x == b.x && a.y == b.y && a.z == b.z && a.w == b.w);
153 }
154
155 public static bool operator !=(float4 a, float4 b)
156 {
157 return !(a == b);
158 }
159
160 public static float4 operator *(float4 v, float s)
161 {
162 return new float4(v.x * s, v.y * s, v.z * s, v.w * s);
163 }
164
165 public static float4 operator *(float s, float4 v)
166 {
167 return new float4(v.x * s, v.y * s, v.z * s, v.w * s);
168 }
169 }
170}
diff --git a/OpenSim/Region/Physics/ConvexDecompositionDotNet/float4x4.cs b/OpenSim/Region/Physics/ConvexDecompositionDotNet/float4x4.cs
new file mode 100644
index 0000000..7d1592f
--- /dev/null
+++ b/OpenSim/Region/Physics/ConvexDecompositionDotNet/float4x4.cs
@@ -0,0 +1,284 @@
1/* The MIT License
2 *
3 * Copyright (c) 2010 Intel Corporation.
4 * All rights reserved.
5 *
6 * Based on the convexdecomposition library from
7 * <http://codesuppository.googlecode.com> by John W. Ratcliff and Stan Melax.
8 *
9 * Permission is hereby granted, free of charge, to any person obtaining a copy
10 * of this software and associated documentation files (the "Software"), to deal
11 * in the Software without restriction, including without limitation the rights
12 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
13 * copies of the Software, and to permit persons to whom the Software is
14 * furnished to do so, subject to the following conditions:
15 *
16 * The above copyright notice and this permission notice shall be included in
17 * all copies or substantial portions of the Software.
18 *
19 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
20 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
21 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
22 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
23 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
24 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
25 * THE SOFTWARE.
26 */
27
28using System;
29using System.Collections.Generic;
30using System.Linq;
31using System.Text;
32
33namespace OpenSim.Region.Physics.ConvexDecompositionDotNet
34{
35 public class float4x4
36 {
37 public float4 x = new float4();
38 public float4 y = new float4();
39 public float4 z = new float4();
40 public float4 w = new float4();
41
42 public float4x4()
43 {
44 }
45
46 public float4x4(float4 _x, float4 _y, float4 _z, float4 _w)
47 {
48 x = new float4(_x);
49 y = new float4(_y);
50 z = new float4(_z);
51 w = new float4(_w);
52 }
53
54 public float4x4(
55 float m00, float m01, float m02, float m03,
56 float m10, float m11, float m12, float m13,
57 float m20, float m21, float m22, float m23,
58 float m30, float m31, float m32, float m33)
59 {
60 x = new float4(m00, m01, m02, m03);
61 y = new float4(m10, m11, m12, m13);
62 z = new float4(m20, m21, m22, m23);
63 w = new float4(m30, m31, m32, m33);
64 }
65
66 public float4x4(float4x4 m)
67 {
68 x = new float4(m.x);
69 y = new float4(m.y);
70 z = new float4(m.z);
71 w = new float4(m.w);
72 }
73
74 public float4 this[int i]
75 {
76 get
77 {
78 switch (i)
79 {
80 case 0: return x;
81 case 1: return y;
82 case 2: return z;
83 case 3: return w;
84 }
85 throw new ArgumentOutOfRangeException();
86 }
87 set
88 {
89 switch (i)
90 {
91 case 0: x = value; return;
92 case 1: y = value; return;
93 case 2: z = value; return;
94 case 3: w = value; return;
95 }
96 throw new ArgumentOutOfRangeException();
97 }
98 }
99
100 public override int GetHashCode()
101 {
102 return x.GetHashCode() ^ y.GetHashCode() ^ z.GetHashCode() ^ w.GetHashCode();
103 }
104
105 public override bool Equals(object obj)
106 {
107 float4x4 m = obj as float4x4;
108 if (m == null)
109 return false;
110
111 return this == m;
112 }
113
114 public static float4x4 operator *(float4x4 a, float4x4 b)
115 {
116 return new float4x4(a.x * b, a.y * b, a.z * b, a.w * b);
117 }
118
119 public static bool operator ==(float4x4 a, float4x4 b)
120 {
121 return (a.x == b.x && a.y == b.y && a.z == b.z && a.w == b.w);
122 }
123
124 public static bool operator !=(float4x4 a, float4x4 b)
125 {
126 return !(a == b);
127 }
128
129 public static float4x4 Inverse(float4x4 m)
130 {
131 float4x4 d = new float4x4();
132 //float dst = d.x.x;
133 float[] tmp = new float[12]; // temp array for pairs
134 float[] src = new float[16]; // array of transpose source matrix
135 float det; // determinant
136 // transpose matrix
137 for (int i = 0; i < 4; i++)
138 {
139 src[i] = m[i].x;
140 src[i + 4] = m[i].y;
141 src[i + 8] = m[i].z;
142 src[i + 12] = m[i].w;
143 }
144 // calculate pairs for first 8 elements (cofactors)
145 tmp[0] = src[10] * src[15];
146 tmp[1] = src[11] * src[14];
147 tmp[2] = src[9] * src[15];
148 tmp[3] = src[11] * src[13];
149 tmp[4] = src[9] * src[14];
150 tmp[5] = src[10] * src[13];
151 tmp[6] = src[8] * src[15];
152 tmp[7] = src[11] * src[12];
153 tmp[8] = src[8] * src[14];
154 tmp[9] = src[10] * src[12];
155 tmp[10] = src[8] * src[13];
156 tmp[11] = src[9] * src[12];
157 // calculate first 8 elements (cofactors)
158 d.x.x = tmp[0]*src[5] + tmp[3]*src[6] + tmp[4]*src[7];
159 d.x.x -= tmp[1]*src[5] + tmp[2]*src[6] + tmp[5]*src[7];
160 d.x.y = tmp[1]*src[4] + tmp[6]*src[6] + tmp[9]*src[7];
161 d.x.y -= tmp[0]*src[4] + tmp[7]*src[6] + tmp[8]*src[7];
162 d.x.z = tmp[2]*src[4] + tmp[7]*src[5] + tmp[10]*src[7];
163 d.x.z -= tmp[3]*src[4] + tmp[6]*src[5] + tmp[11]*src[7];
164 d.x.w = tmp[5]*src[4] + tmp[8]*src[5] + tmp[11]*src[6];
165 d.x.w -= tmp[4]*src[4] + tmp[9]*src[5] + tmp[10]*src[6];
166 d.y.x = tmp[1]*src[1] + tmp[2]*src[2] + tmp[5]*src[3];
167 d.y.x -= tmp[0]*src[1] + tmp[3]*src[2] + tmp[4]*src[3];
168 d.y.y = tmp[0]*src[0] + tmp[7]*src[2] + tmp[8]*src[3];
169 d.y.y -= tmp[1]*src[0] + tmp[6]*src[2] + tmp[9]*src[3];
170 d.y.z = tmp[3]*src[0] + tmp[6]*src[1] + tmp[11]*src[3];
171 d.y.z -= tmp[2]*src[0] + tmp[7]*src[1] + tmp[10]*src[3];
172 d.y.w = tmp[4]*src[0] + tmp[9]*src[1] + tmp[10]*src[2];
173 d.y.w -= tmp[5]*src[0] + tmp[8]*src[1] + tmp[11]*src[2];
174 // calculate pairs for second 8 elements (cofactors)
175 tmp[0] = src[2]*src[7];
176 tmp[1] = src[3]*src[6];
177 tmp[2] = src[1]*src[7];
178 tmp[3] = src[3]*src[5];
179 tmp[4] = src[1]*src[6];
180 tmp[5] = src[2]*src[5];
181 tmp[6] = src[0]*src[7];
182 tmp[7] = src[3]*src[4];
183 tmp[8] = src[0]*src[6];
184 tmp[9] = src[2]*src[4];
185 tmp[10] = src[0]*src[5];
186 tmp[11] = src[1]*src[4];
187 // calculate second 8 elements (cofactors)
188 d.z.x = tmp[0]*src[13] + tmp[3]*src[14] + tmp[4]*src[15];
189 d.z.x -= tmp[1]*src[13] + tmp[2]*src[14] + tmp[5]*src[15];
190 d.z.y = tmp[1]*src[12] + tmp[6]*src[14] + tmp[9]*src[15];
191 d.z.y -= tmp[0]*src[12] + tmp[7]*src[14] + tmp[8]*src[15];
192 d.z.z = tmp[2]*src[12] + tmp[7]*src[13] + tmp[10]*src[15];
193 d.z.z -= tmp[3]*src[12] + tmp[6]*src[13] + tmp[11]*src[15];
194 d.z.w = tmp[5]*src[12] + tmp[8]*src[13] + tmp[11]*src[14];
195 d.z.w-= tmp[4]*src[12] + tmp[9]*src[13] + tmp[10]*src[14];
196 d.w.x = tmp[2]*src[10] + tmp[5]*src[11] + tmp[1]*src[9];
197 d.w.x-= tmp[4]*src[11] + tmp[0]*src[9] + tmp[3]*src[10];
198 d.w.y = tmp[8]*src[11] + tmp[0]*src[8] + tmp[7]*src[10];
199 d.w.y-= tmp[6]*src[10] + tmp[9]*src[11] + tmp[1]*src[8];
200 d.w.z = tmp[6]*src[9] + tmp[11]*src[11] + tmp[3]*src[8];
201 d.w.z-= tmp[10]*src[11] + tmp[2]*src[8] + tmp[7]*src[9];
202 d.w.w = tmp[10]*src[10] + tmp[4]*src[8] + tmp[9]*src[9];
203 d.w.w-= tmp[8]*src[9] + tmp[11]*src[10] + tmp[5]*src[8];
204 // calculate determinant
205 det = src[0] * d.x.x + src[1] * d.x.y + src[2] * d.x.z + src[3] * d.x.w;
206 // calculate matrix inverse
207 det = 1/det;
208 for (int j = 0; j < 4; j++)
209 d[j] *= det;
210 return d;
211 }
212
213 public static float4x4 MatrixRigidInverse(float4x4 m)
214 {
215 float4x4 trans_inverse = MatrixTranslation(-m.w.xyz());
216 float4x4 rot = new float4x4(m);
217 rot.w = new float4(0f, 0f, 0f, 1f);
218 return trans_inverse * MatrixTranspose(rot);
219 }
220 public static float4x4 MatrixTranspose(float4x4 m)
221 {
222 return new float4x4(m.x.x, m.y.x, m.z.x, m.w.x, m.x.y, m.y.y, m.z.y, m.w.y, m.x.z, m.y.z, m.z.z, m.w.z, m.x.w, m.y.w, m.z.w, m.w.w);
223 }
224 public static float4x4 MatrixPerspectiveFov(float fovy, float aspect, float zn, float zf)
225 {
226 float h = 1.0f / (float)Math.Tan(fovy / 2.0f); // view space height
227 float w = h / aspect; // view space width
228 return new float4x4(w, 0, 0, 0, 0, h, 0, 0, 0, 0, zf / (zn - zf), -1, 0, 0, zn * zf / (zn - zf), 0);
229 }
230 public static float4x4 MatrixTranslation(float3 t)
231 {
232 return new float4x4(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, t.x, t.y, t.z, 1);
233 }
234 public static float4x4 MatrixRotationZ(float angle_radians)
235 {
236 float s = (float)Math.Sin(angle_radians);
237 float c = (float)Math.Cos(angle_radians);
238 return new float4x4(c, s, 0, 0, -s, c, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1);
239 }
240 public static float4x4 MatrixLookAt(float3 eye, float3 at, float3 up)
241 {
242 float4x4 m = new float4x4();
243 m.w.w = 1.0f;
244 m.w.setxyz(eye);
245 m.z.setxyz(float3.normalize(eye - at));
246 m.x.setxyz(float3.normalize(float3.cross(up, m.z.xyz())));
247 m.y.setxyz(float3.cross(m.z.xyz(), m.x.xyz()));
248 return MatrixRigidInverse(m);
249 }
250
251 public static float4x4 MatrixFromQuatVec(Quaternion q, float3 v)
252 {
253 // builds a 4x4 transformation matrix based on orientation q and translation v
254 float qx2 = q.x * q.x;
255 float qy2 = q.y * q.y;
256 float qz2 = q.z * q.z;
257
258 float qxqy = q.x * q.y;
259 float qxqz = q.x * q.z;
260 float qxqw = q.x * q.w;
261 float qyqz = q.y * q.z;
262 float qyqw = q.y * q.w;
263 float qzqw = q.z * q.w;
264
265 return new float4x4(
266 1 - 2 * (qy2 + qz2),
267 2 * (qxqy + qzqw),
268 2 * (qxqz - qyqw),
269 0,
270 2 * (qxqy - qzqw),
271 1 - 2 * (qx2 + qz2),
272 2 * (qyqz + qxqw),
273 0,
274 2 * (qxqz + qyqw),
275 2 * (qyqz - qxqw),
276 1 - 2 * (qx2 + qy2),
277 0,
278 v.x,
279 v.y,
280 v.z,
281 1.0f);
282 }
283 }
284}
diff --git a/OpenSim/Region/Physics/ConvexDecompositionDotNet/int3.cs b/OpenSim/Region/Physics/ConvexDecompositionDotNet/int3.cs
new file mode 100644
index 0000000..9c5760d
--- /dev/null
+++ b/OpenSim/Region/Physics/ConvexDecompositionDotNet/int3.cs
@@ -0,0 +1,128 @@
1/* The MIT License
2 *
3 * Copyright (c) 2010 Intel Corporation.
4 * All rights reserved.
5 *
6 * Based on the convexdecomposition library from
7 * <http://codesuppository.googlecode.com> by John W. Ratcliff and Stan Melax.
8 *
9 * Permission is hereby granted, free of charge, to any person obtaining a copy
10 * of this software and associated documentation files (the "Software"), to deal
11 * in the Software without restriction, including without limitation the rights
12 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
13 * copies of the Software, and to permit persons to whom the Software is
14 * furnished to do so, subject to the following conditions:
15 *
16 * The above copyright notice and this permission notice shall be included in
17 * all copies or substantial portions of the Software.
18 *
19 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
20 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
21 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
22 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
23 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
24 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
25 * THE SOFTWARE.
26 */
27
28using System;
29
30namespace OpenSim.Region.Physics.ConvexDecompositionDotNet
31{
32 public class int3
33 {
34 public int x;
35 public int y;
36 public int z;
37
38 public int3()
39 {
40 }
41
42 public int3(int _x, int _y, int _z)
43 {
44 x = _x;
45 y = _y;
46 z = _z;
47 }
48
49 public int this[int i]
50 {
51 get
52 {
53 switch (i)
54 {
55 case 0: return x;
56 case 1: return y;
57 case 2: return z;
58 }
59 throw new ArgumentOutOfRangeException();
60 }
61 set
62 {
63 switch (i)
64 {
65 case 0: x = value; return;
66 case 1: y = value; return;
67 case 2: z = value; return;
68 }
69 throw new ArgumentOutOfRangeException();
70 }
71 }
72
73 public override int GetHashCode()
74 {
75 return x.GetHashCode() ^ y.GetHashCode() ^ z.GetHashCode();
76 }
77
78 public override bool Equals(object obj)
79 {
80 int3 i = obj as int3;
81 if (i == null)
82 return false;
83
84 return this == i;
85 }
86
87 public static bool operator ==(int3 a, int3 b)
88 {
89 // If both are null, or both are same instance, return true.
90 if (System.Object.ReferenceEquals(a, b))
91 return true;
92 // If one is null, but not both, return false.
93 if (((object)a == null) || ((object)b == null))
94 return false;
95
96 for (int i = 0; i < 3; i++)
97 {
98 if (a[i] != b[i])
99 return false;
100 }
101 return true;
102 }
103
104 public static bool operator !=(int3 a, int3 b)
105 {
106 return !(a == b);
107 }
108
109 public static int3 roll3(int3 a)
110 {
111 int tmp = a[0];
112 a[0] = a[1];
113 a[1] = a[2];
114 a[2] = tmp;
115 return a;
116 }
117
118 public static bool isa(int3 a, int3 b)
119 {
120 return (a == b || roll3(a) == b || a == roll3(b));
121 }
122
123 public static bool b2b(int3 a, int3 b)
124 {
125 return isa(a, new int3(b[2], b[1], b[0]));
126 }
127 }
128}
diff --git a/OpenSim/Region/Physics/ConvexDecompositionDotNet/int4.cs b/OpenSim/Region/Physics/ConvexDecompositionDotNet/int4.cs
new file mode 100644
index 0000000..c2b32e5
--- /dev/null
+++ b/OpenSim/Region/Physics/ConvexDecompositionDotNet/int4.cs
@@ -0,0 +1,66 @@
1/* The MIT License
2 *
3 * Copyright (c) 2010 Intel Corporation.
4 * All rights reserved.
5 *
6 * Based on the convexdecomposition library from
7 * <http://codesuppository.googlecode.com> by John W. Ratcliff and Stan Melax.
8 *
9 * Permission is hereby granted, free of charge, to any person obtaining a copy
10 * of this software and associated documentation files (the "Software"), to deal
11 * in the Software without restriction, including without limitation the rights
12 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
13 * copies of the Software, and to permit persons to whom the Software is
14 * furnished to do so, subject to the following conditions:
15 *
16 * The above copyright notice and this permission notice shall be included in
17 * all copies or substantial portions of the Software.
18 *
19 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
20 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
21 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
22 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
23 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
24 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
25 * THE SOFTWARE.
26 */
27
28using System;
29
30namespace OpenSim.Region.Physics.ConvexDecompositionDotNet
31{
32 public class int4
33 {
34 public int x;
35 public int y;
36 public int z;
37 public int w;
38
39 public int4()
40 {
41 }
42
43 public int4(int _x, int _y, int _z, int _w)
44 {
45 x = _x;
46 y = _y;
47 z = _z;
48 w = _w;
49 }
50
51 public int this[int i]
52 {
53 get
54 {
55 switch (i)
56 {
57 case 0: return x;
58 case 1: return y;
59 case 2: return z;
60 case 3: return w;
61 }
62 throw new ArgumentOutOfRangeException();
63 }
64 }
65 }
66}
diff --git a/OpenSim/Region/Physics/Manager/IMesher.cs b/OpenSim/Region/Physics/Manager/IMesher.cs
index 1181b8d..3a9ca1b 100644
--- a/OpenSim/Region/Physics/Manager/IMesher.cs
+++ b/OpenSim/Region/Physics/Manager/IMesher.cs
@@ -38,6 +38,17 @@ namespace OpenSim.Region.Physics.Manager
38 IMesh CreateMesh(String primName, PrimitiveBaseShape primShape, Vector3 size, float lod, bool isPhysical); 38 IMesh CreateMesh(String primName, PrimitiveBaseShape primShape, Vector3 size, float lod, bool isPhysical);
39 } 39 }
40 40
41 // Values for level of detail to be passed to the mesher.
42 // Values origionally chosen for the LOD of sculpties (the sqrt(width*heigth) of sculpt texture)
43 // Lower level of detail reduces the number of vertices used to represent the meshed shape.
44 public enum LevelOfDetail
45 {
46 High = 32,
47 Medium = 16,
48 Low = 8,
49 VeryLow = 4
50 }
51
41 public interface IVertex 52 public interface IVertex
42 { 53 {
43 } 54 }
diff --git a/OpenSim/Region/Physics/Manager/IPhysicsParameters.cs b/OpenSim/Region/Physics/Manager/IPhysicsParameters.cs
new file mode 100755
index 0000000..b8676ba
--- /dev/null
+++ b/OpenSim/Region/Physics/Manager/IPhysicsParameters.cs
@@ -0,0 +1,73 @@
1/*
2 * Copyright (c) Contributors, http://opensimulator.org/
3 * See CONTRIBUTORS.TXT for a full list of copyright holders.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 * * Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * * Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 * * Neither the name of the OpenSimulator Project nor the
13 * names of its contributors may be used to endorse or promote products
14 * derived from this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
17 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19 * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
20 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
27
28using System;
29using System.Collections.Generic;
30using OpenSim.Framework;
31using OpenMetaverse;
32
33namespace OpenSim.Region.Physics.Manager
34{
35 public struct PhysParameterEntry
36 {
37 // flags to say to apply to all or no instances (I wish one could put consts into interfaces)
38 public const uint APPLY_TO_ALL = 0xfffffff3;
39 public const uint APPLY_TO_NONE = 0xfffffff4;
40
41 // values that denote true and false values
42 public const float NUMERIC_TRUE = 1f;
43 public const float NUMERIC_FALSE = 0f;
44
45 public string name;
46 public string desc;
47
48 public PhysParameterEntry(string n, string d)
49 {
50 name = n;
51 desc = d;
52 }
53 }
54
55 // Interface for a physics scene that implements the runtime setting and getting of physics parameters
56 public interface IPhysicsParameters
57 {
58 // Get the list of parameters this physics engine supports
59 PhysParameterEntry[] GetParameterList();
60
61 // Set parameter on a specific or all instances.
62 // Return 'false' if not able to set the parameter.
63 bool SetPhysicsParameter(string parm, float value, uint localID);
64
65 // Get parameter.
66 // Return 'false' if not able to get the parameter.
67 bool GetPhysicsParameter(string parm, out float value);
68
69 // Get parameter from a particular object
70 // TODO:
71 // bool GetPhysicsParameter(string parm, out float value, uint localID);
72 }
73}
diff --git a/OpenSim/Region/Physics/Manager/PhysicsScene.cs b/OpenSim/Region/Physics/Manager/PhysicsScene.cs
index de22fae..72b01ac 100644
--- a/OpenSim/Region/Physics/Manager/PhysicsScene.cs
+++ b/OpenSim/Region/Physics/Manager/PhysicsScene.cs
@@ -37,6 +37,18 @@ namespace OpenSim.Region.Physics.Manager
37 public delegate void physicsCrash(); 37 public delegate void physicsCrash();
38 38
39 public delegate void RaycastCallback(bool hitYN, Vector3 collisionPoint, uint localid, float distance, Vector3 normal); 39 public delegate void RaycastCallback(bool hitYN, Vector3 collisionPoint, uint localid, float distance, Vector3 normal);
40 public delegate void RayCallback(List<ContactResult> list);
41
42 /// <summary>
43 /// Contact result from a raycast.
44 /// </summary>
45 public struct ContactResult
46 {
47 public Vector3 Pos;
48 public float Depth;
49 public uint ConsumerID;
50 public Vector3 Normal;
51 }
40 52
41 public abstract class PhysicsScene 53 public abstract class PhysicsScene
42 { 54 {
@@ -61,7 +73,6 @@ namespace OpenSim.Region.Physics.Manager
61 } 73 }
62 } 74 }
63 75
64
65 public abstract void Initialise(IMesher meshmerizer, IConfigSource config); 76 public abstract void Initialise(IMesher meshmerizer, IConfigSource config);
66 77
67 public abstract PhysicsActor AddAvatar(string avName, Vector3 position, Vector3 size, bool isFlying); 78 public abstract PhysicsActor AddAvatar(string avName, Vector3 position, Vector3 size, bool isFlying);
@@ -75,6 +86,10 @@ namespace OpenSim.Region.Physics.Manager
75 86
76 public abstract void RemoveAvatar(PhysicsActor actor); 87 public abstract void RemoveAvatar(PhysicsActor actor);
77 88
89 /// <summary>
90 /// Remove a prim from the physics scene.
91 /// </summary>
92 /// <param name="prim"></param>
78 public abstract void RemovePrim(PhysicsActor prim); 93 public abstract void RemovePrim(PhysicsActor prim);
79 94
80 //public abstract PhysicsActor AddPrimShape(string primName, PrimitiveBaseShape pbs, Vector3 position, 95 //public abstract PhysicsActor AddPrimShape(string primName, PrimitiveBaseShape pbs, Vector3 position,
@@ -83,17 +98,6 @@ namespace OpenSim.Region.Physics.Manager
83 public abstract PhysicsActor AddPrimShape(string primName, PrimitiveBaseShape pbs, Vector3 position, 98 public abstract PhysicsActor AddPrimShape(string primName, PrimitiveBaseShape pbs, Vector3 position,
84 Vector3 size, Quaternion rotation, bool isPhysical, uint localid); 99 Vector3 size, Quaternion rotation, bool isPhysical, uint localid);
85 100
86 public virtual PhysicsActor AddPrimShape(uint localID, string primName, PrimitiveBaseShape pbs, Vector3 position,
87 Vector3 size, Quaternion rotation, bool isPhysical, uint localid)
88 {
89 PhysicsActor ret = AddPrimShape(primName, pbs, position, size, rotation, isPhysical, localid);
90
91 if (ret != null)
92 ret.LocalID = localID;
93
94 return ret;
95 }
96
97 public virtual float TimeDilation 101 public virtual float TimeDilation
98 { 102 {
99 get { return 1.0f; } 103 get { return 1.0f; }
@@ -226,6 +230,17 @@ namespace OpenSim.Region.Physics.Manager
226 retMethod(false, Vector3.Zero, 0, 999999999999f, Vector3.Zero); 230 retMethod(false, Vector3.Zero, 0, 999999999999f, Vector3.Zero);
227 } 231 }
228 232
233 public virtual void RaycastWorld(Vector3 position, Vector3 direction, float length, int Count, RayCallback retMethod)
234 {
235 if (retMethod != null)
236 retMethod(new List<ContactResult>());
237 }
238
239 public virtual List<ContactResult> RaycastWorld(Vector3 position, Vector3 direction, float length, int Count)
240 {
241 return new List<ContactResult>();
242 }
243
229 private class NullPhysicsScene : PhysicsScene 244 private class NullPhysicsScene : PhysicsScene
230 { 245 {
231 private static int m_workIndicator; 246 private static int m_workIndicator;
diff --git a/OpenSim/Region/Physics/Meshing/Meshmerizer.cs b/OpenSim/Region/Physics/Meshing/Meshmerizer.cs
index b79e1a1..53d5e4c 100644
--- a/OpenSim/Region/Physics/Meshing/Meshmerizer.cs
+++ b/OpenSim/Region/Physics/Meshing/Meshmerizer.cs
@@ -193,67 +193,6 @@ namespace OpenSim.Region.Physics.Meshing
193 m_log.Error("****** PrimMesh Parameters ******\n" + primMesh.ParamsToDisplayString()); 193 m_log.Error("****** PrimMesh Parameters ******\n" + primMesh.ParamsToDisplayString());
194 } 194 }
195 195
196 private ulong GetMeshKey(PrimitiveBaseShape pbs, Vector3 size, float lod)
197 {
198 ulong hash = 5381;
199
200 hash = djb2(hash, pbs.PathCurve);
201 hash = djb2(hash, (byte)((byte)pbs.HollowShape | (byte)pbs.ProfileShape));
202 hash = djb2(hash, pbs.PathBegin);
203 hash = djb2(hash, pbs.PathEnd);
204 hash = djb2(hash, pbs.PathScaleX);
205 hash = djb2(hash, pbs.PathScaleY);
206 hash = djb2(hash, pbs.PathShearX);
207 hash = djb2(hash, pbs.PathShearY);
208 hash = djb2(hash, (byte)pbs.PathTwist);
209 hash = djb2(hash, (byte)pbs.PathTwistBegin);
210 hash = djb2(hash, (byte)pbs.PathRadiusOffset);
211 hash = djb2(hash, (byte)pbs.PathTaperX);
212 hash = djb2(hash, (byte)pbs.PathTaperY);
213 hash = djb2(hash, pbs.PathRevolutions);
214 hash = djb2(hash, (byte)pbs.PathSkew);
215 hash = djb2(hash, pbs.ProfileBegin);
216 hash = djb2(hash, pbs.ProfileEnd);
217 hash = djb2(hash, pbs.ProfileHollow);
218
219 // TODO: Separate scale out from the primitive shape data (after
220 // scaling is supported at the physics engine level)
221 byte[] scaleBytes = size.GetBytes();
222 for (int i = 0; i < scaleBytes.Length; i++)
223 hash = djb2(hash, scaleBytes[i]);
224
225 // Include LOD in hash, accounting for endianness
226 byte[] lodBytes = new byte[4];
227 Buffer.BlockCopy(BitConverter.GetBytes(lod), 0, lodBytes, 0, 4);
228 if (!BitConverter.IsLittleEndian)
229 {
230 Array.Reverse(lodBytes, 0, 4);
231 }
232 for (int i = 0; i < lodBytes.Length; i++)
233 hash = djb2(hash, lodBytes[i]);
234
235 // include sculpt UUID
236 if (pbs.SculptEntry)
237 {
238 scaleBytes = pbs.SculptTexture.GetBytes();
239 for (int i = 0; i < scaleBytes.Length; i++)
240 hash = djb2(hash, scaleBytes[i]);
241 }
242
243 return hash;
244 }
245
246 private ulong djb2(ulong hash, byte c)
247 {
248 return ((hash << 5) + hash) + (ulong)c;
249 }
250
251 private ulong djb2(ulong hash, ushort c)
252 {
253 hash = ((hash << 5) + hash) + (ulong)((byte)c);
254 return ((hash << 5) + hash) + (ulong)(c >> 8);
255 }
256
257 /// <summary> 196 /// <summary>
258 /// Add a submesh to an existing list of coords and faces. 197 /// Add a submesh to an existing list of coords and faces.
259 /// </summary> 198 /// </summary>
@@ -301,16 +240,22 @@ namespace OpenSim.Region.Physics.Meshing
301 } 240 }
302 } 241 }
303 242
243 /// <summary>
244 /// Create a physics mesh from data that comes with the prim. The actual data used depends on the prim type.
245 /// </summary>
246 /// <param name="primName"></param>
247 /// <param name="primShape"></param>
248 /// <param name="size"></param>
249 /// <param name="lod"></param>
250 /// <returns></returns>
304 private Mesh CreateMeshFromPrimMesher(string primName, PrimitiveBaseShape primShape, Vector3 size, float lod) 251 private Mesh CreateMeshFromPrimMesher(string primName, PrimitiveBaseShape primShape, Vector3 size, float lod)
305 { 252 {
306 PrimMesh primMesh; 253// m_log.DebugFormat(
307 PrimMesher.SculptMesh sculptMesh; 254// "[MESH]: Creating physics proxy for {0}, shape {1}",
308 255// primName, (OpenMetaverse.SculptType)primShape.SculptType);
309 List<Coord> coords = new List<Coord>();
310 List<Face> faces = new List<Face>();
311 256
312 Image idata = null; 257 List<Coord> coords;
313 string decodedSculptFileName = ""; 258 List<Face> faces;
314 259
315 if (primShape.SculptEntry) 260 if (primShape.SculptEntry)
316 { 261 {
@@ -319,337 +264,440 @@ namespace OpenSim.Region.Physics.Meshing
319 if (!useMeshiesPhysicsMesh) 264 if (!useMeshiesPhysicsMesh)
320 return null; 265 return null;
321 266
322 m_log.Debug("[MESH]: experimental mesh proxy generation"); 267 if (!GenerateCoordsAndFacesFromPrimMeshData(primName, primShape, size, out coords, out faces))
268 return null;
269 }
270 else
271 {
272 if (!GenerateCoordsAndFacesFromPrimSculptData(primName, primShape, size, lod, out coords, out faces))
273 return null;
274 }
275 }
276 else
277 {
278 if (!GenerateCoordsAndFacesFromPrimShapeData(primName, primShape, size, lod, out coords, out faces))
279 return null;
280 }
323 281
324 OSD meshOsd = null; 282 // Remove the reference to any JPEG2000 sculpt data so it can be GCed
283 primShape.SculptData = Utils.EmptyBytes;
325 284
326 if (primShape.SculptData.Length <= 0) 285 int numCoords = coords.Count;
327 { 286 int numFaces = faces.Count;
328 m_log.Error("[MESH]: asset data is zero length");
329 return null;
330 }
331 287
332 long start = 0; 288 // Create the list of vertices
333 using (MemoryStream data = new MemoryStream(primShape.SculptData)) 289 List<Vertex> vertices = new List<Vertex>();
334 { 290 for (int i = 0; i < numCoords; i++)
335 try 291 {
336 { 292 Coord c = coords[i];
337 OSD osd = OSDParser.DeserializeLLSDBinary(data); 293 vertices.Add(new Vertex(c.X, c.Y, c.Z));
338 if (osd is OSDMap) 294 }
339 meshOsd = (OSDMap)osd;
340 else
341 {
342 m_log.Warn("[Mesh}: unable to cast mesh asset to OSDMap");
343 return null;
344 }
345 }
346 catch (Exception e)
347 {
348 m_log.Error("[MESH]: Exception deserializing mesh asset header:" + e.ToString());
349 }
350 295
351 start = data.Position; 296 Mesh mesh = new Mesh();
352 } 297 // Add the corresponding triangles to the mesh
298 for (int i = 0; i < numFaces; i++)
299 {
300 Face f = faces[i];
301 mesh.Add(new Triangle(vertices[f.v1], vertices[f.v2], vertices[f.v3]));
302 }
303
304 return mesh;
305 }
306
307 /// <summary>
308 /// Generate the co-ords and faces necessary to construct a mesh from the mesh data the accompanies a prim.
309 /// </summary>
310 /// <param name="primName"></param>
311 /// <param name="primShape"></param>
312 /// <param name="size"></param>
313 /// <param name="coords">Coords are added to this list by the method.</param>
314 /// <param name="faces">Faces are added to this list by the method.</param>
315 /// <returns>true if coords and faces were successfully generated, false if not</returns>
316 private bool GenerateCoordsAndFacesFromPrimMeshData(
317 string primName, PrimitiveBaseShape primShape, Vector3 size, out List<Coord> coords, out List<Face> faces)
318 {
319 m_log.DebugFormat("[MESH]: experimental mesh proxy generation for {0}", primName);
320
321 coords = new List<Coord>();
322 faces = new List<Face>();
323 OSD meshOsd = null;
324
325 if (primShape.SculptData.Length <= 0)
326 {
327 m_log.Error("[MESH]: asset data is zero length");
328 return false;
329 }
353 330
354 if (meshOsd is OSDMap) 331 long start = 0;
332 using (MemoryStream data = new MemoryStream(primShape.SculptData))
333 {
334 try
335 {
336 OSD osd = OSDParser.DeserializeLLSDBinary(data);
337 if (osd is OSDMap)
338 meshOsd = (OSDMap)osd;
339 else
355 { 340 {
356 OSDMap physicsParms = null; 341 m_log.Warn("[Mesh}: unable to cast mesh asset to OSDMap");
357 OSDMap map = (OSDMap)meshOsd; 342 return false;
358 if (map.ContainsKey("physics_shape")) 343 }
359 physicsParms = (OSDMap)map["physics_shape"]; // old asset format 344 }
360 else if (map.ContainsKey("physics_mesh")) 345 catch (Exception e)
361 physicsParms = (OSDMap)map["physics_mesh"]; // new asset format 346 {
362 347 m_log.Error("[MESH]: Exception deserializing mesh asset header:" + e.ToString());
363 if (physicsParms == null) 348 }
364 { 349
365 m_log.Warn("[MESH]: no recognized physics mesh found in mesh asset"); 350 start = data.Position;
366 return null; 351 }
367 } 352
353 if (meshOsd is OSDMap)
354 {
355 OSDMap physicsParms = null;
356 OSDMap map = (OSDMap)meshOsd;
357 if (map.ContainsKey("physics_shape"))
358 physicsParms = (OSDMap)map["physics_shape"]; // old asset format
359 else if (map.ContainsKey("physics_mesh"))
360 physicsParms = (OSDMap)map["physics_mesh"]; // new asset format
361
362 if (physicsParms == null)
363 {
364 m_log.Warn("[MESH]: no recognized physics mesh found in mesh asset");
365 return false;
366 }
368 367
369 int physOffset = physicsParms["offset"].AsInteger() + (int)start; 368 int physOffset = physicsParms["offset"].AsInteger() + (int)start;
370 int physSize = physicsParms["size"].AsInteger(); 369 int physSize = physicsParms["size"].AsInteger();
371 370
372 if (physOffset < 0 || physSize == 0) 371 if (physOffset < 0 || physSize == 0)
373 return null; // no mesh data in asset 372 return false; // no mesh data in asset
374 373
375 OSD decodedMeshOsd = new OSD(); 374 OSD decodedMeshOsd = new OSD();
376 byte[] meshBytes = new byte[physSize]; 375 byte[] meshBytes = new byte[physSize];
377 System.Buffer.BlockCopy(primShape.SculptData, physOffset, meshBytes, 0, physSize); 376 System.Buffer.BlockCopy(primShape.SculptData, physOffset, meshBytes, 0, physSize);
378// byte[] decompressed = new byte[physSize * 5]; 377// byte[] decompressed = new byte[physSize * 5];
379 try 378 try
379 {
380 using (MemoryStream inMs = new MemoryStream(meshBytes))
381 {
382 using (MemoryStream outMs = new MemoryStream())
380 { 383 {
381 using (MemoryStream inMs = new MemoryStream(meshBytes)) 384 using (ZOutputStream zOut = new ZOutputStream(outMs))
382 { 385 {
383 using (MemoryStream outMs = new MemoryStream()) 386 byte[] readBuffer = new byte[2048];
387 int readLen = 0;
388 while ((readLen = inMs.Read(readBuffer, 0, readBuffer.Length)) > 0)
384 { 389 {
385 using (ZOutputStream zOut = new ZOutputStream(outMs)) 390 zOut.Write(readBuffer, 0, readLen);
386 {
387 byte[] readBuffer = new byte[2048];
388 int readLen = 0;
389 while ((readLen = inMs.Read(readBuffer, 0, readBuffer.Length)) > 0)
390 {
391 zOut.Write(readBuffer, 0, readLen);
392 }
393 zOut.Flush();
394 outMs.Seek(0, SeekOrigin.Begin);
395
396 byte[] decompressedBuf = outMs.GetBuffer();
397
398 decodedMeshOsd = OSDParser.DeserializeLLSDBinary(decompressedBuf);
399 }
400 } 391 }
392 zOut.Flush();
393 outMs.Seek(0, SeekOrigin.Begin);
394
395 byte[] decompressedBuf = outMs.GetBuffer();
396
397 decodedMeshOsd = OSDParser.DeserializeLLSDBinary(decompressedBuf);
401 } 398 }
402 } 399 }
403 catch (Exception e) 400 }
404 { 401 }
405 m_log.Error("[MESH]: exception decoding physical mesh: " + e.ToString()); 402 catch (Exception e)
406 return null; 403 {
407 } 404 m_log.Error("[MESH]: exception decoding physical mesh: " + e.ToString());
405 return false;
406 }
408 407
409 OSDArray decodedMeshOsdArray = null; 408 OSDArray decodedMeshOsdArray = null;
410 409
411 // physics_shape is an array of OSDMaps, one for each submesh 410 // physics_shape is an array of OSDMaps, one for each submesh
412 if (decodedMeshOsd is OSDArray) 411 if (decodedMeshOsd is OSDArray)
413 { 412 {
414// Console.WriteLine("decodedMeshOsd for {0} - {1}", primName, Util.GetFormattedXml(decodedMeshOsd)); 413// Console.WriteLine("decodedMeshOsd for {0} - {1}", primName, Util.GetFormattedXml(decodedMeshOsd));
415 414
416 decodedMeshOsdArray = (OSDArray)decodedMeshOsd; 415 decodedMeshOsdArray = (OSDArray)decodedMeshOsd;
417 foreach (OSD subMeshOsd in decodedMeshOsdArray) 416 foreach (OSD subMeshOsd in decodedMeshOsdArray)
418 { 417 {
419 if (subMeshOsd is OSDMap) 418 if (subMeshOsd is OSDMap)
420 AddSubMesh(subMeshOsd as OSDMap, size, coords, faces); 419 AddSubMesh(subMeshOsd as OSDMap, size, coords, faces);
421 }
422 }
423 } 420 }
424 } 421 }
425 else 422 }
423
424 return true;
425 }
426
427 /// <summary>
428 /// Generate the co-ords and faces necessary to construct a mesh from the sculpt data the accompanies a prim.
429 /// </summary>
430 /// <param name="primName"></param>
431 /// <param name="primShape"></param>
432 /// <param name="size"></param>
433 /// <param name="lod"></param>
434 /// <param name="coords">Coords are added to this list by the method.</param>
435 /// <param name="faces">Faces are added to this list by the method.</param>
436 /// <returns>true if coords and faces were successfully generated, false if not</returns>
437 private bool GenerateCoordsAndFacesFromPrimSculptData(
438 string primName, PrimitiveBaseShape primShape, Vector3 size, float lod, out List<Coord> coords, out List<Face> faces)
439 {
440 coords = new List<Coord>();
441 faces = new List<Face>();
442 PrimMesher.SculptMesh sculptMesh;
443 Image idata = null;
444 string decodedSculptFileName = "";
445
446 if (cacheSculptMaps && primShape.SculptTexture != UUID.Zero)
447 {
448 decodedSculptFileName = System.IO.Path.Combine(decodedSculptMapPath, "smap_" + primShape.SculptTexture.ToString());
449 try
426 { 450 {
427 if (cacheSculptMaps && primShape.SculptTexture != UUID.Zero) 451 if (File.Exists(decodedSculptFileName))
428 { 452 {
429 decodedSculptFileName = System.IO.Path.Combine(decodedSculptMapPath, "smap_" + primShape.SculptTexture.ToString()); 453 idata = Image.FromFile(decodedSculptFileName);
430 try
431 {
432 if (File.Exists(decodedSculptFileName))
433 {
434 idata = Image.FromFile(decodedSculptFileName);
435 }
436 }
437 catch (Exception e)
438 {
439 m_log.Error("[SCULPT]: unable to load cached sculpt map " + decodedSculptFileName + " " + e.Message);
440
441 }
442 //if (idata != null)
443 // m_log.Debug("[SCULPT]: loaded cached map asset for map ID: " + primShape.SculptTexture.ToString());
444 } 454 }
455 }
456 catch (Exception e)
457 {
458 m_log.Error("[SCULPT]: unable to load cached sculpt map " + decodedSculptFileName + " " + e.Message);
459
460 }
461 //if (idata != null)
462 // m_log.Debug("[SCULPT]: loaded cached map asset for map ID: " + primShape.SculptTexture.ToString());
463 }
464
465 if (idata == null)
466 {
467 if (primShape.SculptData == null || primShape.SculptData.Length == 0)
468 return false;
469
470 try
471 {
472 OpenMetaverse.Imaging.ManagedImage unusedData;
473 OpenMetaverse.Imaging.OpenJPEG.DecodeToImage(primShape.SculptData, out unusedData, out idata);
445 474
446 if (idata == null) 475 if (idata == null)
447 { 476 {
448 if (primShape.SculptData == null || primShape.SculptData.Length == 0) 477 // In some cases it seems that the decode can return a null bitmap without throwing
449 return null; 478 // an exception
479 m_log.WarnFormat("[PHYSICS]: OpenJPEG decoded sculpt data for {0} to a null bitmap. Ignoring.", primName);
450 480
451 try 481 return false;
452 { 482 }
453 OpenMetaverse.Imaging.ManagedImage unusedData;
454 OpenMetaverse.Imaging.OpenJPEG.DecodeToImage(primShape.SculptData, out unusedData, out idata);
455 unusedData = null;
456 483
457 //idata = CSJ2K.J2kImage.FromBytes(primShape.SculptData); 484 unusedData = null;
458 485
459 if (cacheSculptMaps && idata != null) 486 //idata = CSJ2K.J2kImage.FromBytes(primShape.SculptData);
460 {
461 try { idata.Save(decodedSculptFileName, ImageFormat.MemoryBmp); }
462 catch (Exception e) { m_log.Error("[SCULPT]: unable to cache sculpt map " + decodedSculptFileName + " " + e.Message); }
463 }
464 }
465 catch (DllNotFoundException)
466 {
467 m_log.Error("[PHYSICS]: OpenJpeg is not installed correctly on this system. Physics Proxy generation failed. Often times this is because of an old version of GLIBC. You must have version 2.4 or above!");
468 return null;
469 }
470 catch (IndexOutOfRangeException)
471 {
472 m_log.Error("[PHYSICS]: OpenJpeg was unable to decode this. Physics Proxy generation failed");
473 return null;
474 }
475 catch (Exception ex)
476 {
477 m_log.Error("[PHYSICS]: Unable to generate a Sculpty physics proxy. Sculpty texture decode failed: " + ex.Message);
478 return null;
479 }
480 }
481 487
482 PrimMesher.SculptMesh.SculptType sculptType; 488 if (cacheSculptMaps)
483 switch ((OpenMetaverse.SculptType)primShape.SculptType)
484 { 489 {
485 case OpenMetaverse.SculptType.Cylinder: 490 try { idata.Save(decodedSculptFileName, ImageFormat.MemoryBmp); }
486 sculptType = PrimMesher.SculptMesh.SculptType.cylinder; 491 catch (Exception e) { m_log.Error("[SCULPT]: unable to cache sculpt map " + decodedSculptFileName + " " + e.Message); }
487 break;
488 case OpenMetaverse.SculptType.Plane:
489 sculptType = PrimMesher.SculptMesh.SculptType.plane;
490 break;
491 case OpenMetaverse.SculptType.Torus:
492 sculptType = PrimMesher.SculptMesh.SculptType.torus;
493 break;
494 case OpenMetaverse.SculptType.Sphere:
495 sculptType = PrimMesher.SculptMesh.SculptType.sphere;
496 break;
497 default:
498 sculptType = PrimMesher.SculptMesh.SculptType.plane;
499 break;
500 } 492 }
493 }
494 catch (DllNotFoundException)
495 {
496 m_log.Error("[PHYSICS]: OpenJpeg is not installed correctly on this system. Physics Proxy generation failed. Often times this is because of an old version of GLIBC. You must have version 2.4 or above!");
497 return false;
498 }
499 catch (IndexOutOfRangeException)
500 {
501 m_log.Error("[PHYSICS]: OpenJpeg was unable to decode this. Physics Proxy generation failed");
502 return false;
503 }
504 catch (Exception ex)
505 {
506 m_log.Error("[PHYSICS]: Unable to generate a Sculpty physics proxy. Sculpty texture decode failed: " + ex.Message);
507 return false;
508 }
509 }
510
511 PrimMesher.SculptMesh.SculptType sculptType;
512 switch ((OpenMetaverse.SculptType)primShape.SculptType)
513 {
514 case OpenMetaverse.SculptType.Cylinder:
515 sculptType = PrimMesher.SculptMesh.SculptType.cylinder;
516 break;
517 case OpenMetaverse.SculptType.Plane:
518 sculptType = PrimMesher.SculptMesh.SculptType.plane;
519 break;
520 case OpenMetaverse.SculptType.Torus:
521 sculptType = PrimMesher.SculptMesh.SculptType.torus;
522 break;
523 case OpenMetaverse.SculptType.Sphere:
524 sculptType = PrimMesher.SculptMesh.SculptType.sphere;
525 break;
526 default:
527 sculptType = PrimMesher.SculptMesh.SculptType.plane;
528 break;
529 }
501 530
502 bool mirror = ((primShape.SculptType & 128) != 0); 531 bool mirror = ((primShape.SculptType & 128) != 0);
503 bool invert = ((primShape.SculptType & 64) != 0); 532 bool invert = ((primShape.SculptType & 64) != 0);
504 533
505 sculptMesh = new PrimMesher.SculptMesh((Bitmap)idata, sculptType, (int)lod, false, mirror, invert); 534 sculptMesh = new PrimMesher.SculptMesh((Bitmap)idata, sculptType, (int)lod, false, mirror, invert);
506
507 idata.Dispose();
508 535
509 sculptMesh.DumpRaw(baseDir, primName, "primMesh"); 536 idata.Dispose();
510 537
511 sculptMesh.Scale(size.X, size.Y, size.Z); 538 sculptMesh.DumpRaw(baseDir, primName, "primMesh");
512 539
513 coords = sculptMesh.coords; 540 sculptMesh.Scale(size.X, size.Y, size.Z);
514 faces = sculptMesh.faces; 541
542 coords = sculptMesh.coords;
543 faces = sculptMesh.faces;
544
545 return true;
546 }
547
548 /// <summary>
549 /// Generate the co-ords and faces necessary to construct a mesh from the shape data the accompanies a prim.
550 /// </summary>
551 /// <param name="primName"></param>
552 /// <param name="primShape"></param>
553 /// <param name="size"></param>
554 /// <param name="coords">Coords are added to this list by the method.</param>
555 /// <param name="faces">Faces are added to this list by the method.</param>
556 /// <returns>true if coords and faces were successfully generated, false if not</returns>
557 private bool GenerateCoordsAndFacesFromPrimShapeData(
558 string primName, PrimitiveBaseShape primShape, Vector3 size, float lod, out List<Coord> coords, out List<Face> faces)
559 {
560 PrimMesh primMesh;
561 coords = new List<Coord>();
562 faces = new List<Face>();
563
564 float pathShearX = primShape.PathShearX < 128 ? (float)primShape.PathShearX * 0.01f : (float)(primShape.PathShearX - 256) * 0.01f;
565 float pathShearY = primShape.PathShearY < 128 ? (float)primShape.PathShearY * 0.01f : (float)(primShape.PathShearY - 256) * 0.01f;
566 float pathBegin = (float)primShape.PathBegin * 2.0e-5f;
567 float pathEnd = 1.0f - (float)primShape.PathEnd * 2.0e-5f;
568 float pathScaleX = (float)(primShape.PathScaleX - 100) * 0.01f;
569 float pathScaleY = (float)(primShape.PathScaleY - 100) * 0.01f;
570
571 float profileBegin = (float)primShape.ProfileBegin * 2.0e-5f;
572 float profileEnd = 1.0f - (float)primShape.ProfileEnd * 2.0e-5f;
573 float profileHollow = (float)primShape.ProfileHollow * 2.0e-5f;
574 if (profileHollow > 0.95f)
575 profileHollow = 0.95f;
576
577 int sides = 4;
578 LevelOfDetail iLOD = (LevelOfDetail)lod;
579 if ((primShape.ProfileCurve & 0x07) == (byte)ProfileShape.EquilateralTriangle)
580 sides = 3;
581 else if ((primShape.ProfileCurve & 0x07) == (byte)ProfileShape.Circle)
582 {
583 switch (iLOD)
584 {
585 case LevelOfDetail.High: sides = 24; break;
586 case LevelOfDetail.Medium: sides = 12; break;
587 case LevelOfDetail.Low: sides = 6; break;
588 case LevelOfDetail.VeryLow: sides = 3; break;
589 default: sides = 24; break;
515 } 590 }
516 } 591 }
517 else 592 else if ((primShape.ProfileCurve & 0x07) == (byte)ProfileShape.HalfCircle)
593 { // half circle, prim is a sphere
594 switch (iLOD)
595 {
596 case LevelOfDetail.High: sides = 24; break;
597 case LevelOfDetail.Medium: sides = 12; break;
598 case LevelOfDetail.Low: sides = 6; break;
599 case LevelOfDetail.VeryLow: sides = 3; break;
600 default: sides = 24; break;
601 }
602
603 profileBegin = 0.5f * profileBegin + 0.5f;
604 profileEnd = 0.5f * profileEnd + 0.5f;
605 }
606
607 int hollowSides = sides;
608 if (primShape.HollowShape == HollowShape.Circle)
518 { 609 {
519 float pathShearX = primShape.PathShearX < 128 ? (float)primShape.PathShearX * 0.01f : (float)(primShape.PathShearX - 256) * 0.01f; 610 switch (iLOD)
520 float pathShearY = primShape.PathShearY < 128 ? (float)primShape.PathShearY * 0.01f : (float)(primShape.PathShearY - 256) * 0.01f; 611 {
521 float pathBegin = (float)primShape.PathBegin * 2.0e-5f; 612 case LevelOfDetail.High: hollowSides = 24; break;
522 float pathEnd = 1.0f - (float)primShape.PathEnd * 2.0e-5f; 613 case LevelOfDetail.Medium: hollowSides = 12; break;
523 float pathScaleX = (float)(primShape.PathScaleX - 100) * 0.01f; 614 case LevelOfDetail.Low: hollowSides = 6; break;
524 float pathScaleY = (float)(primShape.PathScaleY - 100) * 0.01f; 615 case LevelOfDetail.VeryLow: hollowSides = 3; break;
525 616 default: hollowSides = 24; break;
526 float profileBegin = (float)primShape.ProfileBegin * 2.0e-5f;
527 float profileEnd = 1.0f - (float)primShape.ProfileEnd * 2.0e-5f;
528 float profileHollow = (float)primShape.ProfileHollow * 2.0e-5f;
529 if (profileHollow > 0.95f)
530 profileHollow = 0.95f;
531
532 int sides = 4;
533 if ((primShape.ProfileCurve & 0x07) == (byte)ProfileShape.EquilateralTriangle)
534 sides = 3;
535 else if ((primShape.ProfileCurve & 0x07) == (byte)ProfileShape.Circle)
536 sides = 24;
537 else if ((primShape.ProfileCurve & 0x07) == (byte)ProfileShape.HalfCircle)
538 { // half circle, prim is a sphere
539 sides = 24;
540
541 profileBegin = 0.5f * profileBegin + 0.5f;
542 profileEnd = 0.5f * profileEnd + 0.5f;
543 } 617 }
618 }
619 else if (primShape.HollowShape == HollowShape.Square)
620 hollowSides = 4;
621 else if (primShape.HollowShape == HollowShape.Triangle)
622 hollowSides = 3;
544 623
545 int hollowSides = sides; 624 primMesh = new PrimMesh(sides, profileBegin, profileEnd, profileHollow, hollowSides);
546 if (primShape.HollowShape == HollowShape.Circle)
547 hollowSides = 24;
548 else if (primShape.HollowShape == HollowShape.Square)
549 hollowSides = 4;
550 else if (primShape.HollowShape == HollowShape.Triangle)
551 hollowSides = 3;
552 625
553 primMesh = new PrimMesh(sides, profileBegin, profileEnd, profileHollow, hollowSides); 626 if (primMesh.errorMessage != null)
627 if (primMesh.errorMessage.Length > 0)
628 m_log.Error("[ERROR] " + primMesh.errorMessage);
554 629
555 if (primMesh.errorMessage != null) 630 primMesh.topShearX = pathShearX;
556 if (primMesh.errorMessage.Length > 0) 631 primMesh.topShearY = pathShearY;
557 m_log.Error("[ERROR] " + primMesh.errorMessage); 632 primMesh.pathCutBegin = pathBegin;
633 primMesh.pathCutEnd = pathEnd;
558 634
559 primMesh.topShearX = pathShearX; 635 if (primShape.PathCurve == (byte)Extrusion.Straight || primShape.PathCurve == (byte) Extrusion.Flexible)
560 primMesh.topShearY = pathShearY; 636 {
561 primMesh.pathCutBegin = pathBegin; 637 primMesh.twistBegin = primShape.PathTwistBegin * 18 / 10;
562 primMesh.pathCutEnd = pathEnd; 638 primMesh.twistEnd = primShape.PathTwist * 18 / 10;
639 primMesh.taperX = pathScaleX;
640 primMesh.taperY = pathScaleY;
563 641
564 if (primShape.PathCurve == (byte)Extrusion.Straight || primShape.PathCurve == (byte) Extrusion.Flexible) 642 if (profileBegin < 0.0f || profileBegin >= profileEnd || profileEnd > 1.0f)
565 { 643 {
566 primMesh.twistBegin = primShape.PathTwistBegin * 18 / 10; 644 ReportPrimError("*** CORRUPT PRIM!! ***", primName, primMesh);
567 primMesh.twistEnd = primShape.PathTwist * 18 / 10; 645 if (profileBegin < 0.0f) profileBegin = 0.0f;
568 primMesh.taperX = pathScaleX; 646 if (profileEnd > 1.0f) profileEnd = 1.0f;
569 primMesh.taperY = pathScaleY; 647 }
570
571 if (profileBegin < 0.0f || profileBegin >= profileEnd || profileEnd > 1.0f)
572 {
573 ReportPrimError("*** CORRUPT PRIM!! ***", primName, primMesh);
574 if (profileBegin < 0.0f) profileBegin = 0.0f;
575 if (profileEnd > 1.0f) profileEnd = 1.0f;
576 }
577#if SPAM 648#if SPAM
578 m_log.Debug("****** PrimMesh Parameters (Linear) ******\n" + primMesh.ParamsToDisplayString()); 649 m_log.Debug("****** PrimMesh Parameters (Linear) ******\n" + primMesh.ParamsToDisplayString());
579#endif 650#endif
580 try 651 try
581 { 652 {
582 primMesh.ExtrudeLinear(); 653 primMesh.ExtrudeLinear();
583 }
584 catch (Exception ex)
585 {
586 ReportPrimError("Extrusion failure: exception: " + ex.ToString(), primName, primMesh);
587 return null;
588 }
589 } 654 }
590 else 655 catch (Exception ex)
591 { 656 {
592 primMesh.holeSizeX = (200 - primShape.PathScaleX) * 0.01f; 657 ReportPrimError("Extrusion failure: exception: " + ex.ToString(), primName, primMesh);
593 primMesh.holeSizeY = (200 - primShape.PathScaleY) * 0.01f; 658 return false;
594 primMesh.radius = 0.01f * primShape.PathRadiusOffset; 659 }
595 primMesh.revolutions = 1.0f + 0.015f * primShape.PathRevolutions; 660 }
596 primMesh.skew = 0.01f * primShape.PathSkew; 661 else
597 primMesh.twistBegin = primShape.PathTwistBegin * 36 / 10; 662 {
598 primMesh.twistEnd = primShape.PathTwist * 36 / 10; 663 primMesh.holeSizeX = (200 - primShape.PathScaleX) * 0.01f;
599 primMesh.taperX = primShape.PathTaperX * 0.01f; 664 primMesh.holeSizeY = (200 - primShape.PathScaleY) * 0.01f;
600 primMesh.taperY = primShape.PathTaperY * 0.01f; 665 primMesh.radius = 0.01f * primShape.PathRadiusOffset;
601 666 primMesh.revolutions = 1.0f + 0.015f * primShape.PathRevolutions;
602 if (profileBegin < 0.0f || profileBegin >= profileEnd || profileEnd > 1.0f) 667 primMesh.skew = 0.01f * primShape.PathSkew;
603 { 668 primMesh.twistBegin = primShape.PathTwistBegin * 36 / 10;
604 ReportPrimError("*** CORRUPT PRIM!! ***", primName, primMesh); 669 primMesh.twistEnd = primShape.PathTwist * 36 / 10;
605 if (profileBegin < 0.0f) profileBegin = 0.0f; 670 primMesh.taperX = primShape.PathTaperX * 0.01f;
606 if (profileEnd > 1.0f) profileEnd = 1.0f; 671 primMesh.taperY = primShape.PathTaperY * 0.01f;
607 } 672
673 if (profileBegin < 0.0f || profileBegin >= profileEnd || profileEnd > 1.0f)
674 {
675 ReportPrimError("*** CORRUPT PRIM!! ***", primName, primMesh);
676 if (profileBegin < 0.0f) profileBegin = 0.0f;
677 if (profileEnd > 1.0f) profileEnd = 1.0f;
678 }
608#if SPAM 679#if SPAM
609 m_log.Debug("****** PrimMesh Parameters (Circular) ******\n" + primMesh.ParamsToDisplayString()); 680 m_log.Debug("****** PrimMesh Parameters (Circular) ******\n" + primMesh.ParamsToDisplayString());
610#endif 681#endif
611 try 682 try
612 { 683 {
613 primMesh.ExtrudeCircular(); 684 primMesh.ExtrudeCircular();
614 } 685 }
615 catch (Exception ex) 686 catch (Exception ex)
616 { 687 {
617 ReportPrimError("Extrusion failure: exception: " + ex.ToString(), primName, primMesh); 688 ReportPrimError("Extrusion failure: exception: " + ex.ToString(), primName, primMesh);
618 return null; 689 return false;
619 }
620 } 690 }
621
622 primMesh.DumpRaw(baseDir, primName, "primMesh");
623
624 primMesh.Scale(size.X, size.Y, size.Z);
625
626 coords = primMesh.coords;
627 faces = primMesh.faces;
628 } 691 }
629 692
630 // Remove the reference to any JPEG2000 sculpt data so it can be GCed 693 primMesh.DumpRaw(baseDir, primName, "primMesh");
631 primShape.SculptData = Utils.EmptyBytes;
632 694
633 int numCoords = coords.Count; 695 primMesh.Scale(size.X, size.Y, size.Z);
634 int numFaces = faces.Count;
635
636 // Create the list of vertices
637 List<Vertex> vertices = new List<Vertex>();
638 for (int i = 0; i < numCoords; i++)
639 {
640 Coord c = coords[i];
641 vertices.Add(new Vertex(c.X, c.Y, c.Z));
642 }
643 696
644 Mesh mesh = new Mesh(); 697 coords = primMesh.coords;
645 // Add the corresponding triangles to the mesh 698 faces = primMesh.faces;
646 for (int i = 0; i < numFaces; i++)
647 {
648 Face f = faces[i];
649 mesh.Add(new Triangle(vertices[f.v1], vertices[f.v2], vertices[f.v3]));
650 }
651 699
652 return mesh; 700 return true;
653 } 701 }
654 702
655 public IMesh CreateMesh(String primName, PrimitiveBaseShape primShape, Vector3 size, float lod) 703 public IMesh CreateMesh(String primName, PrimitiveBaseShape primShape, Vector3 size, float lod)
@@ -668,8 +716,7 @@ namespace OpenSim.Region.Physics.Meshing
668 716
669 // If this mesh has been created already, return it instead of creating another copy 717 // If this mesh has been created already, return it instead of creating another copy
670 // For large regions with 100k+ prims and hundreds of copies of each, this can save a GB or more of memory 718 // For large regions with 100k+ prims and hundreds of copies of each, this can save a GB or more of memory
671 719 key = primShape.GetMeshKey(size, lod);
672 key = GetMeshKey(primShape, size, lod);
673 if (m_uniqueMeshes.TryGetValue(key, out mesh)) 720 if (m_uniqueMeshes.TryGetValue(key, out mesh))
674 return mesh; 721 return mesh;
675 722
diff --git a/OpenSim/Region/Physics/OdePlugin/ODECharacter.cs b/OpenSim/Region/Physics/OdePlugin/ODECharacter.cs
index 0e7dd81..c165a41 100644
--- a/OpenSim/Region/Physics/OdePlugin/ODECharacter.cs
+++ b/OpenSim/Region/Physics/OdePlugin/ODECharacter.cs
@@ -258,7 +258,11 @@ namespace OpenSim.Region.Physics.OdePlugin
258 public override bool Flying 258 public override bool Flying
259 { 259 {
260 get { return flying; } 260 get { return flying; }
261 set { flying = value; } 261 set
262 {
263 flying = value;
264// m_log.DebugFormat("[PHYSICS]: Set OdeCharacter Flying to {0}", flying);
265 }
262 } 266 }
263 267
264 /// <summary> 268 /// <summary>
@@ -305,10 +309,12 @@ namespace OpenSim.Region.Physics.OdePlugin
305 { 309 {
306 m_iscolliding = true; 310 m_iscolliding = true;
307 } 311 }
312
308 if (m_wascolliding != m_iscolliding) 313 if (m_wascolliding != m_iscolliding)
309 { 314 {
310 //base.SendCollisionUpdate(new CollisionEventUpdate()); 315 //base.SendCollisionUpdate(new CollisionEventUpdate());
311 } 316 }
317
312 m_wascolliding = m_iscolliding; 318 m_wascolliding = m_iscolliding;
313 } 319 }
314 } 320 }
@@ -1219,18 +1225,23 @@ namespace OpenSim.Region.Physics.OdePlugin
1219 { 1225 {
1220 m_requestedUpdateFrequency = ms; 1226 m_requestedUpdateFrequency = ms;
1221 m_eventsubscription = ms; 1227 m_eventsubscription = ms;
1222 _parent_scene.addCollisionEventReporting(this); 1228 _parent_scene.AddCollisionEventReporting(this);
1223 } 1229 }
1230
1224 public override void UnSubscribeEvents() 1231 public override void UnSubscribeEvents()
1225 { 1232 {
1226 _parent_scene.remCollisionEventReporting(this); 1233 _parent_scene.RemoveCollisionEventReporting(this);
1227 m_requestedUpdateFrequency = 0; 1234 m_requestedUpdateFrequency = 0;
1228 m_eventsubscription = 0; 1235 m_eventsubscription = 0;
1229 } 1236 }
1237
1230 public void AddCollisionEvent(uint CollidedWith, ContactPoint contact) 1238 public void AddCollisionEvent(uint CollidedWith, ContactPoint contact)
1231 { 1239 {
1232 if (m_eventsubscription > 0) 1240 if (m_eventsubscription > 0)
1233 { 1241 {
1242// m_log.DebugFormat(
1243// "[PHYSICS]: Adding collision event for {0}, collidedWith {1}, contact {2}", "", CollidedWith, contact);
1244
1234 CollisionEventsThisFrame.addCollider(CollidedWith, contact); 1245 CollisionEventsThisFrame.addCollider(CollidedWith, contact);
1235 } 1246 }
1236 } 1247 }
@@ -1247,6 +1258,7 @@ namespace OpenSim.Region.Physics.OdePlugin
1247 m_eventsubscription = 0; 1258 m_eventsubscription = 0;
1248 } 1259 }
1249 } 1260 }
1261
1250 public override bool SubscribedEvents() 1262 public override bool SubscribedEvents()
1251 { 1263 {
1252 if (m_eventsubscription > 0) 1264 if (m_eventsubscription > 0)
diff --git a/OpenSim/Region/Physics/OdePlugin/ODEPrim.cs b/OpenSim/Region/Physics/OdePlugin/ODEPrim.cs
index 5fe0775..0a4fc51 100644
--- a/OpenSim/Region/Physics/OdePlugin/ODEPrim.cs
+++ b/OpenSim/Region/Physics/OdePlugin/ODEPrim.cs
@@ -61,6 +61,22 @@ namespace OpenSim.Region.Physics.OdePlugin
61 { 61 {
62 private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); 62 private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
63 63
64 private bool m_isphysical;
65
66 /// <summary>
67 /// Is this prim subject to physics? Even if not, it's still solid for collision purposes.
68 /// </summary>
69 public override bool IsPhysical
70 {
71 get { return m_isphysical; }
72 set
73 {
74 m_isphysical = value;
75 if (!m_isphysical) // Zero the remembered last velocity
76 m_lastVelocity = Vector3.Zero;
77 }
78 }
79
64 private Vector3 _position; 80 private Vector3 _position;
65 private Vector3 _velocity; 81 private Vector3 _velocity;
66 private Vector3 _torque; 82 private Vector3 _torque;
@@ -138,12 +154,15 @@ namespace OpenSim.Region.Physics.OdePlugin
138 private List<Vector3> m_forcelist = new List<Vector3>(); 154 private List<Vector3> m_forcelist = new List<Vector3>();
139 private List<Vector3> m_angularforcelist = new List<Vector3>(); 155 private List<Vector3> m_angularforcelist = new List<Vector3>();
140 156
141 private IMesh _mesh;
142 private PrimitiveBaseShape _pbs; 157 private PrimitiveBaseShape _pbs;
143 private OdeScene _parent_scene; 158 private OdeScene _parent_scene;
159
160 /// <summary>
161 /// The physics space which contains prim geometries
162 /// </summary>
144 public IntPtr m_targetSpace = IntPtr.Zero; 163 public IntPtr m_targetSpace = IntPtr.Zero;
164
145 public IntPtr prim_geom; 165 public IntPtr prim_geom;
146 public IntPtr prev_geom;
147 public IntPtr _triMeshData; 166 public IntPtr _triMeshData;
148 167
149 private IntPtr _linkJointGroup = IntPtr.Zero; 168 private IntPtr _linkJointGroup = IntPtr.Zero;
@@ -153,7 +172,6 @@ namespace OpenSim.Region.Physics.OdePlugin
153 private List<OdePrim> childrenPrim = new List<OdePrim>(); 172 private List<OdePrim> childrenPrim = new List<OdePrim>();
154 173
155 private bool iscolliding; 174 private bool iscolliding;
156 private bool m_isphysical;
157 private bool m_isSelected; 175 private bool m_isSelected;
158 176
159 internal bool m_isVolumeDetect; // If true, this prim only detects collisions but doesn't collide actively 177 internal bool m_isVolumeDetect; // If true, this prim only detects collisions but doesn't collide actively
@@ -188,7 +206,7 @@ namespace OpenSim.Region.Physics.OdePlugin
188 internal int m_material = (int)Material.Wood; 206 internal int m_material = (int)Material.Wood;
189 207
190 public OdePrim(String primName, OdeScene parent_scene, Vector3 pos, Vector3 size, 208 public OdePrim(String primName, OdeScene parent_scene, Vector3 pos, Vector3 size,
191 Quaternion rotation, IMesh mesh, PrimitiveBaseShape pbs, bool pisPhysical, CollisionLocker dode) 209 Quaternion rotation, PrimitiveBaseShape pbs, bool pisPhysical, CollisionLocker dode)
192 { 210 {
193 Name = primName; 211 Name = primName;
194 m_vehicle = new ODEDynamics(); 212 m_vehicle = new ODEDynamics();
@@ -208,9 +226,7 @@ namespace OpenSim.Region.Physics.OdePlugin
208 // m_tensor = parent_scene.bodyMotorJointMaxforceTensor; 226 // m_tensor = parent_scene.bodyMotorJointMaxforceTensor;
209 body_autodisable_frames = parent_scene.bodyFramesAutoDisable; 227 body_autodisable_frames = parent_scene.bodyFramesAutoDisable;
210 228
211
212 prim_geom = IntPtr.Zero; 229 prim_geom = IntPtr.Zero;
213 prev_geom = IntPtr.Zero;
214 230
215 if (!pos.IsFinite()) 231 if (!pos.IsFinite())
216 { 232 {
@@ -233,20 +249,21 @@ namespace OpenSim.Region.Physics.OdePlugin
233 249
234 _orientation = rotation; 250 _orientation = rotation;
235 m_taintrot = _orientation; 251 m_taintrot = _orientation;
236 _mesh = mesh;
237 _pbs = pbs; 252 _pbs = pbs;
238 253
239 _parent_scene = parent_scene; 254 _parent_scene = parent_scene;
240 m_targetSpace = (IntPtr)0; 255 m_targetSpace = (IntPtr)0;
241 256
242 if (pos.Z < 0) 257 if (pos.Z < 0)
243 m_isphysical = false; 258 {
259 IsPhysical = false;
260 }
244 else 261 else
245 { 262 {
246 m_isphysical = pisPhysical; 263 IsPhysical = pisPhysical;
247 // If we're physical, we need to be in the master space for now. 264 // If we're physical, we need to be in the master space for now.
248 // linksets *should* be in a space together.. but are not currently 265 // linksets *should* be in a space together.. but are not currently
249 if (m_isphysical) 266 if (IsPhysical)
250 m_targetSpace = _parent_scene.space; 267 m_targetSpace = _parent_scene.space;
251 } 268 }
252 269
@@ -289,7 +306,7 @@ namespace OpenSim.Region.Physics.OdePlugin
289 // through it while it's selected 306 // through it while it's selected
290 m_collisionscore = 0; 307 m_collisionscore = 0;
291 308
292 if ((m_isphysical && !_zeroFlag) || !value) 309 if ((IsPhysical && !_zeroFlag) || !value)
293 { 310 {
294 m_taintselected = value; 311 m_taintselected = value;
295 _parent_scene.AddPhysicsActorTaint(this); 312 _parent_scene.AddPhysicsActorTaint(this);
@@ -305,15 +322,21 @@ namespace OpenSim.Region.Physics.OdePlugin
305 } 322 }
306 } 323 }
307 324
325 /// <summary>
326 /// Set a new geometry for this prim.
327 /// </summary>
328 /// <param name="geom"></param>
308 public void SetGeom(IntPtr geom) 329 public void SetGeom(IntPtr geom)
309 { 330 {
310 prev_geom = prim_geom;
311 prim_geom = geom; 331 prim_geom = geom;
312//Console.WriteLine("SetGeom to " + prim_geom + " for " + Name); 332//Console.WriteLine("SetGeom to " + prim_geom + " for " + Name);
313 if (prim_geom != IntPtr.Zero) 333 if (prim_geom != IntPtr.Zero)
314 { 334 {
315 d.GeomSetCategoryBits(prim_geom, (int)m_collisionCategories); 335 d.GeomSetCategoryBits(prim_geom, (int)m_collisionCategories);
316 d.GeomSetCollideBits(prim_geom, (int)m_collisionFlags); 336 d.GeomSetCollideBits(prim_geom, (int)m_collisionFlags);
337
338 _parent_scene.geom_name_map[prim_geom] = Name;
339 _parent_scene.actor_name_map[prim_geom] = this;
317 } 340 }
318 341
319 if (childPrim) 342 if (childPrim)
@@ -332,7 +355,7 @@ namespace OpenSim.Region.Physics.OdePlugin
332 { 355 {
333 if (!childPrim) 356 if (!childPrim)
334 { 357 {
335 if (m_isphysical && Body != IntPtr.Zero) 358 if (IsPhysical && Body != IntPtr.Zero)
336 { 359 {
337 d.BodyEnable(Body); 360 d.BodyEnable(Body);
338 if (m_vehicle.Type != Vehicle.TYPE_NONE) 361 if (m_vehicle.Type != Vehicle.TYPE_NONE)
@@ -347,12 +370,15 @@ namespace OpenSim.Region.Physics.OdePlugin
347 { 370 {
348 m_disabled = true; 371 m_disabled = true;
349 372
350 if (m_isphysical && Body != IntPtr.Zero) 373 if (IsPhysical && Body != IntPtr.Zero)
351 { 374 {
352 d.BodyDisable(Body); 375 d.BodyDisable(Body);
353 } 376 }
354 } 377 }
355 378
379 /// <summary>
380 /// Make a prim subject to physics.
381 /// </summary>
356 public void enableBody() 382 public void enableBody()
357 { 383 {
358 // Don't enable this body if we're a child prim 384 // Don't enable this body if we're a child prim
@@ -638,7 +664,7 @@ namespace OpenSim.Region.Physics.OdePlugin
638 float profileEnd; 664 float profileEnd;
639 665
640 if (_pbs.PathCurve == (byte)Extrusion.Straight || _pbs.PathCurve == (byte)Extrusion.Flexible) 666 if (_pbs.PathCurve == (byte)Extrusion.Straight || _pbs.PathCurve == (byte)Extrusion.Flexible)
641 { 667 {
642 taperX1 = _pbs.PathScaleX * 0.01f; 668 taperX1 = _pbs.PathScaleX * 0.01f;
643 if (taperX1 > 1.0f) 669 if (taperX1 > 1.0f)
644 taperX1 = 2.0f - taperX1; 670 taperX1 = 2.0f - taperX1;
@@ -648,9 +674,9 @@ namespace OpenSim.Region.Physics.OdePlugin
648 if (taperY1 > 1.0f) 674 if (taperY1 > 1.0f)
649 taperY1 = 2.0f - taperY1; 675 taperY1 = 2.0f - taperY1;
650 taperY = 1.0f - taperY1; 676 taperY = 1.0f - taperY1;
651 } 677 }
652 else 678 else
653 { 679 {
654 taperX = _pbs.PathTaperX * 0.01f; 680 taperX = _pbs.PathTaperX * 0.01f;
655 if (taperX < 0.0f) 681 if (taperX < 0.0f)
656 taperX = -taperX; 682 taperX = -taperX;
@@ -660,9 +686,7 @@ namespace OpenSim.Region.Physics.OdePlugin
660 if (taperY < 0.0f) 686 if (taperY < 0.0f)
661 taperY = -taperY; 687 taperY = -taperY;
662 taperY1 = 1.0f - taperY; 688 taperY1 = 1.0f - taperY;
663 689 }
664 }
665
666 690
667 volume *= (taperX1 * taperY1 + 0.5f * (taperX1 * taperY + taperX * taperY1) + 0.3333333333f * taperX * taperY); 691 volume *= (taperX1 * taperY1 + 0.5f * (taperX1 * taperY + taperX * taperY1) + 0.3333333333f * taperX * taperY);
668 692
@@ -730,6 +754,9 @@ namespace OpenSim.Region.Physics.OdePlugin
730 } 754 }
731 } 755 }
732 756
757 /// <summary>
758 /// Stop a prim from being subject to physics.
759 /// </summary>
733 public void disableBody() 760 public void disableBody()
734 { 761 {
735 //this kills the body so things like 'mesh' can re-create it. 762 //this kills the body so things like 'mesh' can re-create it.
@@ -780,6 +807,7 @@ namespace OpenSim.Region.Physics.OdePlugin
780 Body = IntPtr.Zero; 807 Body = IntPtr.Zero;
781 } 808 }
782 } 809 }
810
783 m_disabled = true; 811 m_disabled = true;
784 m_collisionscore = 0; 812 m_collisionscore = 0;
785 } 813 }
@@ -846,7 +874,6 @@ namespace OpenSim.Region.Physics.OdePlugin
846 return; 874 return;
847 } 875 }
848 876
849
850 // if (IsPhysical && Body == (IntPtr) 0) 877 // if (IsPhysical && Body == (IntPtr) 0)
851 // { 878 // {
852 // Recreate the body 879 // Recreate the body
@@ -859,7 +886,9 @@ namespace OpenSim.Region.Physics.OdePlugin
859 886
860 public void ProcessTaints(float timestep) 887 public void ProcessTaints(float timestep)
861 { 888 {
862Console.WriteLine("ProcessTaints for " + Name); 889#if SPAM
890Console.WriteLine("ZProcessTaints for " + Name);
891#endif
863 if (m_taintadd) 892 if (m_taintadd)
864 { 893 {
865 changeadd(timestep); 894 changeadd(timestep);
@@ -887,7 +916,7 @@ Console.WriteLine("ProcessTaints for " + Name);
887 } 916 }
888 } 917 }
889 918
890 if (m_taintPhysics != m_isphysical && !(m_taintparent != _parent)) 919 if (m_taintPhysics != IsPhysical && !(m_taintparent != _parent))
891 changePhysicsStatus(timestep); 920 changePhysicsStatus(timestep);
892 921
893 if (!_size.ApproxEquals(m_taintsize, 0f)) 922 if (!_size.ApproxEquals(m_taintsize, 0f))
@@ -969,7 +998,7 @@ Console.WriteLine("ProcessTaints for " + Name);
969 OdePrim obj = (OdePrim)m_taintparent; 998 OdePrim obj = (OdePrim)m_taintparent;
970 //obj.disableBody(); 999 //obj.disableBody();
971//Console.WriteLine("changelink calls ParentPrim"); 1000//Console.WriteLine("changelink calls ParentPrim");
972 obj.ParentPrim(this); 1001 obj.AddChildPrim(this);
973 1002
974 /* 1003 /*
975 if (obj.Body != (IntPtr)0 && Body != (IntPtr)0 && obj.Body != Body) 1004 if (obj.Body != (IntPtr)0 && Body != (IntPtr)0 && obj.Body != Body)
@@ -1006,14 +1035,16 @@ Console.WriteLine("ProcessTaints for " + Name);
1006 } 1035 }
1007 1036
1008 _parent = m_taintparent; 1037 _parent = m_taintparent;
1009 m_taintPhysics = m_isphysical; 1038 m_taintPhysics = IsPhysical;
1010 } 1039 }
1011 1040
1012 // I'm the parent 1041 /// <summary>
1013 // prim is the child 1042 /// Add a child prim to this parent prim.
1014 public void ParentPrim(OdePrim prim) 1043 /// </summary>
1044 /// <param name="prim">Child prim</param>
1045 public void AddChildPrim(OdePrim prim)
1015 { 1046 {
1016//Console.WriteLine("ParentPrim " + Name); 1047//Console.WriteLine("AddChildPrim " + Name);
1017 if (this.m_localID != prim.m_localID) 1048 if (this.m_localID != prim.m_localID)
1018 { 1049 {
1019 if (Body == IntPtr.Zero) 1050 if (Body == IntPtr.Zero)
@@ -1036,7 +1067,6 @@ Console.WriteLine("ProcessTaints for " + Name);
1036 d.MassSetZero(out m2); 1067 d.MassSetZero(out m2);
1037 d.MassSetBoxTotal(out m2, prim.CalculateMass(), prm._size.X, prm._size.Y, prm._size.Z); 1068 d.MassSetBoxTotal(out m2, prim.CalculateMass(), prm._size.X, prm._size.Y, prm._size.Z);
1038 1069
1039
1040 d.Quaternion quat = new d.Quaternion(); 1070 d.Quaternion quat = new d.Quaternion();
1041 quat.W = prm._orientation.W; 1071 quat.W = prm._orientation.W;
1042 quat.X = prm._orientation.X; 1072 quat.X = prm._orientation.X;
@@ -1106,6 +1136,7 @@ Console.WriteLine("ProcessTaints for " + Name);
1106 prm.Body = Body; 1136 prm.Body = Body;
1107 _parent_scene.addActivePrim(prm); 1137 _parent_scene.addActivePrim(prm);
1108 } 1138 }
1139
1109 m_collisionCategories |= CollisionCategories.Body; 1140 m_collisionCategories |= CollisionCategories.Body;
1110 m_collisionFlags |= (CollisionCategories.Land | CollisionCategories.Wind); 1141 m_collisionFlags |= (CollisionCategories.Land | CollisionCategories.Wind);
1111 1142
@@ -1114,7 +1145,6 @@ Console.WriteLine("ProcessTaints for " + Name);
1114//Console.WriteLine(" Post GeomSetCategoryBits 2"); 1145//Console.WriteLine(" Post GeomSetCategoryBits 2");
1115 d.GeomSetCollideBits(prim_geom, (int)m_collisionFlags); 1146 d.GeomSetCollideBits(prim_geom, (int)m_collisionFlags);
1116 1147
1117
1118 d.Quaternion quat2 = new d.Quaternion(); 1148 d.Quaternion quat2 = new d.Quaternion();
1119 quat2.W = _orientation.W; 1149 quat2.W = _orientation.W;
1120 quat2.X = _orientation.X; 1150 quat2.X = _orientation.X;
@@ -1136,7 +1166,6 @@ Console.WriteLine("ProcessTaints for " + Name);
1136 d.BodySetAutoDisableFlag(Body, true); 1166 d.BodySetAutoDisableFlag(Body, true);
1137 d.BodySetAutoDisableSteps(Body, body_autodisable_frames); 1167 d.BodySetAutoDisableSteps(Body, body_autodisable_frames);
1138 1168
1139
1140 m_interpenetrationcount = 0; 1169 m_interpenetrationcount = 0;
1141 m_collisionscore = 0; 1170 m_collisionscore = 0;
1142 m_disabled = false; 1171 m_disabled = false;
@@ -1147,7 +1176,9 @@ Console.WriteLine("ProcessTaints for " + Name);
1147 createAMotor(m_angularlock); 1176 createAMotor(m_angularlock);
1148 } 1177 }
1149 d.BodySetPosition(Body, Position.X, Position.Y, Position.Z); 1178 d.BodySetPosition(Body, Position.X, Position.Y, Position.Z);
1150 if (m_vehicle.Type != Vehicle.TYPE_NONE) m_vehicle.Enable(Body, _parent_scene); 1179 if (m_vehicle.Type != Vehicle.TYPE_NONE)
1180 m_vehicle.Enable(Body, _parent_scene);
1181
1151 _parent_scene.addActivePrim(this); 1182 _parent_scene.addActivePrim(this);
1152 } 1183 }
1153 } 1184 }
@@ -1157,7 +1188,7 @@ Console.WriteLine("ProcessTaints for " + Name);
1157 1188
1158 private void ChildSetGeom(OdePrim odePrim) 1189 private void ChildSetGeom(OdePrim odePrim)
1159 { 1190 {
1160 //if (m_isphysical && Body != IntPtr.Zero) 1191 //if (IsPhysical && Body != IntPtr.Zero)
1161 lock (childrenPrim) 1192 lock (childrenPrim)
1162 { 1193 {
1163 foreach (OdePrim prm in childrenPrim) 1194 foreach (OdePrim prm in childrenPrim)
@@ -1173,7 +1204,6 @@ Console.WriteLine("ProcessTaints for " + Name);
1173 } 1204 }
1174 disableBody(); 1205 disableBody();
1175 1206
1176
1177 if (Body != IntPtr.Zero) 1207 if (Body != IntPtr.Zero)
1178 { 1208 {
1179 _parent_scene.remActivePrim(this); 1209 _parent_scene.remActivePrim(this);
@@ -1184,10 +1214,9 @@ Console.WriteLine("ProcessTaints for " + Name);
1184 foreach (OdePrim prm in childrenPrim) 1214 foreach (OdePrim prm in childrenPrim)
1185 { 1215 {
1186//Console.WriteLine("ChildSetGeom calls ParentPrim"); 1216//Console.WriteLine("ChildSetGeom calls ParentPrim");
1187 ParentPrim(prm); 1217 AddChildPrim(prm);
1188 } 1218 }
1189 } 1219 }
1190
1191 } 1220 }
1192 1221
1193 private void ChildDelink(OdePrim odePrim) 1222 private void ChildDelink(OdePrim odePrim)
@@ -1224,7 +1253,7 @@ Console.WriteLine("ProcessTaints for " + Name);
1224 foreach (OdePrim prm in childrenPrim) 1253 foreach (OdePrim prm in childrenPrim)
1225 { 1254 {
1226//Console.WriteLine("ChildDelink calls ParentPrim"); 1255//Console.WriteLine("ChildDelink calls ParentPrim");
1227 ParentPrim(prm); 1256 AddChildPrim(prm);
1228 } 1257 }
1229 } 1258 }
1230 } 1259 }
@@ -1258,7 +1287,7 @@ Console.WriteLine("ProcessTaints for " + Name);
1258 // first 50 again. then the last 50 are disabled. then the first 50, which were just woken 1287 // first 50 again. then the last 50 are disabled. then the first 50, which were just woken
1259 // up, start simulating again, which in turn wakes up the last 50. 1288 // up, start simulating again, which in turn wakes up the last 50.
1260 1289
1261 if (m_isphysical) 1290 if (IsPhysical)
1262 { 1291 {
1263 disableBodySoft(); 1292 disableBodySoft();
1264 } 1293 }
@@ -1269,7 +1298,7 @@ Console.WriteLine("ProcessTaints for " + Name);
1269 d.GeomSetCollideBits(prim_geom, (int)m_collisionFlags); 1298 d.GeomSetCollideBits(prim_geom, (int)m_collisionFlags);
1270 } 1299 }
1271 1300
1272 if (m_isphysical) 1301 if (IsPhysical)
1273 { 1302 {
1274 disableBodySoft(); 1303 disableBodySoft();
1275 } 1304 }
@@ -1278,7 +1307,7 @@ Console.WriteLine("ProcessTaints for " + Name);
1278 { 1307 {
1279 m_collisionCategories = CollisionCategories.Geom; 1308 m_collisionCategories = CollisionCategories.Geom;
1280 1309
1281 if (m_isphysical) 1310 if (IsPhysical)
1282 m_collisionCategories |= CollisionCategories.Body; 1311 m_collisionCategories |= CollisionCategories.Body;
1283 1312
1284 m_collisionFlags = m_default_collisionFlags; 1313 m_collisionFlags = m_default_collisionFlags;
@@ -1293,7 +1322,8 @@ Console.WriteLine("ProcessTaints for " + Name);
1293 d.GeomSetCategoryBits(prim_geom, (int)m_collisionCategories); 1322 d.GeomSetCategoryBits(prim_geom, (int)m_collisionCategories);
1294 d.GeomSetCollideBits(prim_geom, (int)m_collisionFlags); 1323 d.GeomSetCollideBits(prim_geom, (int)m_collisionFlags);
1295 } 1324 }
1296 if (m_isphysical) 1325
1326 if (IsPhysical)
1297 { 1327 {
1298 if (Body != IntPtr.Zero) 1328 if (Body != IntPtr.Zero)
1299 { 1329 {
@@ -1312,7 +1342,7 @@ Console.WriteLine("ProcessTaints for " + Name);
1312 { 1342 {
1313 m_taintposition = _position; 1343 m_taintposition = _position;
1314 m_taintrot = _orientation; 1344 m_taintrot = _orientation;
1315 m_taintPhysics = m_isphysical; 1345 m_taintPhysics = IsPhysical;
1316 m_taintselected = m_isSelected; 1346 m_taintselected = m_isSelected;
1317 m_taintsize = _size; 1347 m_taintsize = _size;
1318 m_taintshape = false; 1348 m_taintshape = false;
@@ -1321,12 +1351,19 @@ Console.WriteLine("ProcessTaints for " + Name);
1321 m_taintVelocity = Vector3.Zero; 1351 m_taintVelocity = Vector3.Zero;
1322 } 1352 }
1323 1353
1324 public void CreateGeom(IntPtr m_targetSpace, IMesh _mesh) 1354 /// <summary>
1355 /// Create a geometry for the given mesh in the given target space.
1356 /// </summary>
1357 /// <param name="m_targetSpace"></param>
1358 /// <param name="mesh">If null, then a mesh is used that is based on the profile shape data.</param>
1359 public void CreateGeom(IntPtr m_targetSpace, IMesh mesh)
1325 { 1360 {
1326//Console.WriteLine("CreateGeom:"); 1361#if SPAM
1327 if (_mesh != null) 1362Console.WriteLine("CreateGeom:");
1363#endif
1364 if (mesh != null)
1328 { 1365 {
1329 setMesh(_parent_scene, _mesh); 1366 setMesh(_parent_scene, mesh);
1330 } 1367 }
1331 else 1368 else
1332 { 1369 {
@@ -1399,6 +1436,39 @@ Console.WriteLine("ProcessTaints for " + Name);
1399 } 1436 }
1400 } 1437 }
1401 1438
1439 /// <summary>
1440 /// Remove the existing geom from this prim.
1441 /// </summary>
1442 /// <param name="m_targetSpace"></param>
1443 /// <param name="mesh">If null, then a mesh is used that is based on the profile shape data.</param>
1444 /// <returns>true if the geom was successfully removed, false if it was already gone or the remove failed.</returns>
1445 public bool RemoveGeom()
1446 {
1447 if (prim_geom != IntPtr.Zero)
1448 {
1449 try
1450 {
1451 _parent_scene.geom_name_map.Remove(prim_geom);
1452 _parent_scene.actor_name_map.Remove(prim_geom);
1453 d.GeomDestroy(prim_geom);
1454 prim_geom = IntPtr.Zero;
1455 }
1456 catch (System.AccessViolationException)
1457 {
1458 prim_geom = IntPtr.Zero;
1459 m_log.ErrorFormat("[PHYSICS]: PrimGeom dead for {0}", Name);
1460
1461 return false;
1462 }
1463
1464 return true;
1465 }
1466 else
1467 {
1468 return false;
1469 }
1470 }
1471
1402 public void changeadd(float timestep) 1472 public void changeadd(float timestep)
1403 { 1473 {
1404 int[] iprimspaceArrItem = _parent_scene.calculateSpaceArrayItemFromPos(_position); 1474 int[] iprimspaceArrItem = _parent_scene.calculateSpaceArrayItemFromPos(_position);
@@ -1409,15 +1479,14 @@ Console.WriteLine("ProcessTaints for " + Name);
1409 1479
1410 m_targetSpace = targetspace; 1480 m_targetSpace = targetspace;
1411 1481
1412 if (_mesh == null) 1482 IMesh mesh = null;
1483
1484 if (_parent_scene.needsMeshing(_pbs))
1413 { 1485 {
1414 if (_parent_scene.needsMeshing(_pbs)) 1486 // Don't need to re-enable body.. it's done in SetMesh
1415 { 1487 mesh = _parent_scene.mesher.CreateMesh(Name, _pbs, _size, _parent_scene.meshSculptLOD, IsPhysical);
1416 // Don't need to re-enable body.. it's done in SetMesh 1488 // createmesh returns null when it's a shape that isn't a cube.
1417 _mesh = _parent_scene.mesher.CreateMesh(Name, _pbs, _size, _parent_scene.meshSculptLOD, IsPhysical); 1489 // m_log.Debug(m_localID);
1418 // createmesh returns null when it's a shape that isn't a cube.
1419 // m_log.Debug(m_localID);
1420 }
1421 } 1490 }
1422 1491
1423 lock (_parent_scene.OdeLock) 1492 lock (_parent_scene.OdeLock)
@@ -1425,7 +1494,7 @@ Console.WriteLine("ProcessTaints for " + Name);
1425#if SPAM 1494#if SPAM
1426Console.WriteLine("changeadd 1"); 1495Console.WriteLine("changeadd 1");
1427#endif 1496#endif
1428 CreateGeom(m_targetSpace, _mesh); 1497 CreateGeom(m_targetSpace, mesh);
1429 1498
1430 if (prim_geom != IntPtr.Zero) 1499 if (prim_geom != IntPtr.Zero)
1431 { 1500 {
@@ -1438,15 +1507,12 @@ Console.WriteLine("changeadd 1");
1438 d.GeomSetQuaternion(prim_geom, ref myrot); 1507 d.GeomSetQuaternion(prim_geom, ref myrot);
1439 } 1508 }
1440 1509
1441 if (m_isphysical && Body == IntPtr.Zero) 1510 if (IsPhysical && Body == IntPtr.Zero)
1442 { 1511 {
1443 enableBody(); 1512 enableBody();
1444 } 1513 }
1445 } 1514 }
1446 1515
1447 _parent_scene.geom_name_map[prim_geom] = this.Name;
1448 _parent_scene.actor_name_map[prim_geom] = (PhysicsActor)this;
1449
1450 changeSelectedStatus(timestep); 1516 changeSelectedStatus(timestep);
1451 1517
1452 m_taintadd = false; 1518 m_taintadd = false;
@@ -1454,9 +1520,8 @@ Console.WriteLine("changeadd 1");
1454 1520
1455 public void changemove(float timestep) 1521 public void changemove(float timestep)
1456 { 1522 {
1457 if (m_isphysical) 1523 if (IsPhysical)
1458 { 1524 {
1459
1460 if (!m_disabled && !m_taintremove && !childPrim) 1525 if (!m_disabled && !m_taintremove && !childPrim)
1461 { 1526 {
1462 if (Body == IntPtr.Zero) 1527 if (Body == IntPtr.Zero)
@@ -1788,7 +1853,7 @@ Console.WriteLine(" JointCreateFixed");
1788 { 1853 {
1789 // KF: If this is a root prim do BodySet 1854 // KF: If this is a root prim do BodySet
1790 d.BodySetQuaternion(Body, ref myrot); 1855 d.BodySetQuaternion(Body, ref myrot);
1791 if (m_isphysical) 1856 if (IsPhysical)
1792 { 1857 {
1793 if (!m_angularlock.ApproxEquals(Vector3.One, 0f)) 1858 if (!m_angularlock.ApproxEquals(Vector3.One, 0f))
1794 createAMotor(m_angularlock); 1859 createAMotor(m_angularlock);
@@ -1825,7 +1890,7 @@ Console.WriteLine(" JointCreateFixed");
1825 1890
1826 public void changePhysicsStatus(float timestep) 1891 public void changePhysicsStatus(float timestep)
1827 { 1892 {
1828 if (m_isphysical == true) 1893 if (IsPhysical)
1829 { 1894 {
1830 if (Body == IntPtr.Zero) 1895 if (Body == IntPtr.Zero)
1831 { 1896 {
@@ -1845,25 +1910,12 @@ Console.WriteLine(" JointCreateFixed");
1845 { 1910 {
1846 if (_pbs.SculptEntry && _parent_scene.meshSculptedPrim) 1911 if (_pbs.SculptEntry && _parent_scene.meshSculptedPrim)
1847 { 1912 {
1848 1913 RemoveGeom();
1849 1914
1850 if (prim_geom != IntPtr.Zero)
1851 {
1852 try
1853 {
1854 d.GeomDestroy(prim_geom);
1855 prim_geom = IntPtr.Zero;
1856 _mesh = null;
1857 }
1858 catch (System.AccessViolationException)
1859 {
1860 prim_geom = IntPtr.Zero;
1861 m_log.ErrorFormat("[PHYSICS]: PrimGeom dead for {0}", Name);
1862 }
1863 }
1864//Console.WriteLine("changePhysicsStatus for " + Name); 1915//Console.WriteLine("changePhysicsStatus for " + Name);
1865 changeadd(2f); 1916 changeadd(2f);
1866 } 1917 }
1918
1867 if (childPrim) 1919 if (childPrim)
1868 { 1920 {
1869 if (_parent != null) 1921 if (_parent != null)
@@ -1882,7 +1934,7 @@ Console.WriteLine(" JointCreateFixed");
1882 changeSelectedStatus(timestep); 1934 changeSelectedStatus(timestep);
1883 1935
1884 resetCollisionAccounting(); 1936 resetCollisionAccounting();
1885 m_taintPhysics = m_isphysical; 1937 m_taintPhysics = IsPhysical;
1886 } 1938 }
1887 1939
1888 public void changesize(float timestamp) 1940 public void changesize(float timestamp)
@@ -1891,18 +1943,10 @@ Console.WriteLine(" JointCreateFixed");
1891 m_log.DebugFormat("[ODE PRIM]: Called changesize"); 1943 m_log.DebugFormat("[ODE PRIM]: Called changesize");
1892#endif 1944#endif
1893 1945
1894 string oldname = _parent_scene.geom_name_map[prim_geom];
1895
1896 if (_size.X <= 0) _size.X = 0.01f; 1946 if (_size.X <= 0) _size.X = 0.01f;
1897 if (_size.Y <= 0) _size.Y = 0.01f; 1947 if (_size.Y <= 0) _size.Y = 0.01f;
1898 if (_size.Z <= 0) _size.Z = 0.01f; 1948 if (_size.Z <= 0) _size.Z = 0.01f;
1899 1949
1900 // Cleanup of old prim geometry
1901 if (_mesh != null)
1902 {
1903 // TODO: Cleanup meshing here
1904 }
1905
1906 //kill body to rebuild 1950 //kill body to rebuild
1907 if (IsPhysical && Body != IntPtr.Zero) 1951 if (IsPhysical && Body != IntPtr.Zero)
1908 { 1952 {
@@ -1926,10 +1970,12 @@ Console.WriteLine(" JointCreateFixed");
1926 d.SpaceRemove(m_targetSpace, prim_geom); 1970 d.SpaceRemove(m_targetSpace, prim_geom);
1927 } 1971 }
1928 1972
1929 d.GeomDestroy(prim_geom); 1973 RemoveGeom();
1930 prim_geom = IntPtr.Zero; 1974
1931 // we don't need to do space calculation because the client sends a position update also. 1975 // we don't need to do space calculation because the client sends a position update also.
1932 1976
1977 IMesh mesh = null;
1978
1933 // Construction of new prim 1979 // Construction of new prim
1934 if (_parent_scene.needsMeshing(_pbs)) 1980 if (_parent_scene.needsMeshing(_pbs))
1935 { 1981 {
@@ -1939,28 +1985,11 @@ Console.WriteLine(" JointCreateFixed");
1939 meshlod = _parent_scene.MeshSculptphysicalLOD; 1985 meshlod = _parent_scene.MeshSculptphysicalLOD;
1940 // Don't need to re-enable body.. it's done in SetMesh 1986 // Don't need to re-enable body.. it's done in SetMesh
1941 1987
1942 IMesh mesh = null;
1943
1944 if (_parent_scene.needsMeshing(_pbs)) 1988 if (_parent_scene.needsMeshing(_pbs))
1945 mesh = _parent_scene.mesher.CreateMesh(oldname, _pbs, _size, meshlod, IsPhysical); 1989 mesh = _parent_scene.mesher.CreateMesh(Name, _pbs, _size, meshlod, IsPhysical);
1946
1947 //IMesh mesh = _parent_scene.mesher.CreateMesh(oldname, _pbs, _size, meshlod, IsPhysical);
1948#if SPAM
1949Console.WriteLine("changesize 1");
1950#endif
1951 CreateGeom(m_targetSpace, mesh);
1952 }
1953 else
1954 {
1955 _mesh = null;
1956
1957#if SPAM
1958Console.WriteLine("changesize 2");
1959#endif
1960
1961 CreateGeom(m_targetSpace, _mesh);
1962 } 1990 }
1963 1991
1992 CreateGeom(m_targetSpace, mesh);
1964 d.GeomSetPosition(prim_geom, _position.X, _position.Y, _position.Z); 1993 d.GeomSetPosition(prim_geom, _position.X, _position.Y, _position.Z);
1965 d.Quaternion myrot = new d.Quaternion(); 1994 d.Quaternion myrot = new d.Quaternion();
1966 myrot.X = _orientation.X; 1995 myrot.X = _orientation.X;
@@ -1978,8 +2007,6 @@ Console.WriteLine("changesize 2");
1978 d.BodyEnable(Body); 2007 d.BodyEnable(Body);
1979 } 2008 }
1980 2009
1981 _parent_scene.geom_name_map[prim_geom] = oldname;
1982
1983 changeSelectedStatus(timestamp); 2010 changeSelectedStatus(timestamp);
1984 if (childPrim) 2011 if (childPrim)
1985 { 2012 {
@@ -2013,8 +2040,6 @@ Console.WriteLine("changesize 2");
2013 2040
2014 public void changeshape(float timestamp) 2041 public void changeshape(float timestamp)
2015 { 2042 {
2016 string oldname = _parent_scene.geom_name_map[prim_geom];
2017
2018 // Cleanup of old prim geometry and Bodies 2043 // Cleanup of old prim geometry and Bodies
2019 if (IsPhysical && Body != IntPtr.Zero) 2044 if (IsPhysical && Body != IntPtr.Zero)
2020 { 2045 {
@@ -2031,23 +2056,17 @@ Console.WriteLine("changesize 2");
2031 disableBody(); 2056 disableBody();
2032 } 2057 }
2033 } 2058 }
2034 try
2035 {
2036 d.GeomDestroy(prim_geom);
2037 }
2038 catch (System.AccessViolationException)
2039 {
2040 prim_geom = IntPtr.Zero;
2041 m_log.ErrorFormat("[PHYSICS]: PrimGeom dead for {0}", Name);
2042 }
2043 2059
2044 prim_geom = IntPtr.Zero; 2060 RemoveGeom();
2061
2045 // we don't need to do space calculation because the client sends a position update also. 2062 // we don't need to do space calculation because the client sends a position update also.
2046 if (_size.X <= 0) _size.X = 0.01f; 2063 if (_size.X <= 0) _size.X = 0.01f;
2047 if (_size.Y <= 0) _size.Y = 0.01f; 2064 if (_size.Y <= 0) _size.Y = 0.01f;
2048 if (_size.Z <= 0) _size.Z = 0.01f; 2065 if (_size.Z <= 0) _size.Z = 0.01f;
2049 // Construction of new prim 2066 // Construction of new prim
2050 2067
2068 IMesh mesh = null;
2069
2051 if (_parent_scene.needsMeshing(_pbs)) 2070 if (_parent_scene.needsMeshing(_pbs))
2052 { 2071 {
2053 // Don't need to re-enable body.. it's done in CreateMesh 2072 // Don't need to re-enable body.. it's done in CreateMesh
@@ -2056,23 +2075,11 @@ Console.WriteLine("changesize 2");
2056 if (IsPhysical) 2075 if (IsPhysical)
2057 meshlod = _parent_scene.MeshSculptphysicalLOD; 2076 meshlod = _parent_scene.MeshSculptphysicalLOD;
2058 2077
2059 IMesh mesh = _parent_scene.mesher.CreateMesh(oldname, _pbs, _size, meshlod, IsPhysical);
2060 // createmesh returns null when it doesn't mesh. 2078 // createmesh returns null when it doesn't mesh.
2061#if SPAM 2079 mesh = _parent_scene.mesher.CreateMesh(Name, _pbs, _size, meshlod, IsPhysical);
2062Console.WriteLine("changeshape needed meshing");
2063#endif
2064 CreateGeom(m_targetSpace, mesh);
2065 }
2066 else
2067 {
2068 _mesh = null;
2069
2070#if SPAM
2071Console.WriteLine("changeshape not need meshing");
2072#endif
2073 CreateGeom(m_targetSpace, null);
2074 } 2080 }
2075 2081
2082 CreateGeom(m_targetSpace, mesh);
2076 d.GeomSetPosition(prim_geom, _position.X, _position.Y, _position.Z); 2083 d.GeomSetPosition(prim_geom, _position.X, _position.Y, _position.Z);
2077 d.Quaternion myrot = new d.Quaternion(); 2084 d.Quaternion myrot = new d.Quaternion();
2078 //myrot.W = _orientation.w; 2085 //myrot.W = _orientation.w;
@@ -2093,7 +2100,6 @@ Console.WriteLine("changeshape not need meshing");
2093 d.BodyEnable(Body); 2100 d.BodyEnable(Body);
2094 } 2101 }
2095 } 2102 }
2096 _parent_scene.geom_name_map[prim_geom] = oldname;
2097 2103
2098 changeSelectedStatus(timestamp); 2104 changeSelectedStatus(timestamp);
2099 if (childPrim) 2105 if (childPrim)
@@ -2104,6 +2110,7 @@ Console.WriteLine("changeshape not need meshing");
2104 parent.ChildSetGeom(this); 2110 parent.ChildSetGeom(this);
2105 } 2111 }
2106 } 2112 }
2113
2107 resetCollisionAccounting(); 2114 resetCollisionAccounting();
2108 m_taintshape = false; 2115 m_taintshape = false;
2109 } 2116 }
@@ -2215,16 +2222,6 @@ Console.WriteLine("changeshape not need meshing");
2215 m_taintVelocity = Vector3.Zero; 2222 m_taintVelocity = Vector3.Zero;
2216 } 2223 }
2217 2224
2218 public override bool IsPhysical
2219 {
2220 get { return m_isphysical; }
2221 set {
2222 m_isphysical = value;
2223 if (!m_isphysical) // Zero the remembered last velocity
2224 m_lastVelocity = Vector3.Zero;
2225 }
2226 }
2227
2228 public void setPrimForRemoval() 2225 public void setPrimForRemoval()
2229 { 2226 {
2230 m_taintremove = true; 2227 m_taintremove = true;
@@ -2283,6 +2280,7 @@ Console.WriteLine("changeshape not need meshing");
2283 if (value.IsFinite()) 2280 if (value.IsFinite())
2284 { 2281 {
2285 _size = value; 2282 _size = value;
2283// m_log.DebugFormat("[PHYSICS]: Set size on {0} to {1}", Name, value);
2286 } 2284 }
2287 else 2285 else
2288 { 2286 {
@@ -2343,7 +2341,7 @@ Console.WriteLine("changeshape not need meshing");
2343 { 2341 {
2344 lock (_parent_scene.OdeLock) 2342 lock (_parent_scene.OdeLock)
2345 { 2343 {
2346 m_isVolumeDetect = (param!=0); 2344 m_isVolumeDetect = (param != 0);
2347 } 2345 }
2348 } 2346 }
2349 2347
@@ -2402,7 +2400,7 @@ Console.WriteLine("changeshape not need meshing");
2402 { 2400 {
2403 get 2401 get
2404 { 2402 {
2405 if (!m_isphysical || Body == IntPtr.Zero) 2403 if (!IsPhysical || Body == IntPtr.Zero)
2406 return Vector3.Zero; 2404 return Vector3.Zero;
2407 2405
2408 return _torque; 2406 return _torque;
@@ -2984,12 +2982,12 @@ Console.WriteLine("changeshape not need meshing");
2984 public override void SubscribeEvents(int ms) 2982 public override void SubscribeEvents(int ms)
2985 { 2983 {
2986 m_eventsubscription = ms; 2984 m_eventsubscription = ms;
2987 _parent_scene.addCollisionEventReporting(this); 2985 _parent_scene.AddCollisionEventReporting(this);
2988 } 2986 }
2989 2987
2990 public override void UnSubscribeEvents() 2988 public override void UnSubscribeEvents()
2991 { 2989 {
2992 _parent_scene.remCollisionEventReporting(this); 2990 _parent_scene.RemoveCollisionEventReporting(this);
2993 m_eventsubscription = 0; 2991 m_eventsubscription = 0;
2994 } 2992 }
2995 2993
@@ -2997,6 +2995,7 @@ Console.WriteLine("changeshape not need meshing");
2997 { 2995 {
2998 if (CollisionEventsThisFrame == null) 2996 if (CollisionEventsThisFrame == null)
2999 CollisionEventsThisFrame = new CollisionEventUpdate(); 2997 CollisionEventsThisFrame = new CollisionEventUpdate();
2998
3000 CollisionEventsThisFrame.addCollider(CollidedWith, contact); 2999 CollisionEventsThisFrame.addCollider(CollidedWith, contact);
3001 } 3000 }
3002 3001
diff --git a/OpenSim/Region/Physics/OdePlugin/ODERayCastRequestManager.cs b/OpenSim/Region/Physics/OdePlugin/ODERayCastRequestManager.cs
index 15ccddc..9d7aa94 100644
--- a/OpenSim/Region/Physics/OdePlugin/ODERayCastRequestManager.cs
+++ b/OpenSim/Region/Physics/OdePlugin/ODERayCastRequestManager.cs
@@ -45,11 +45,16 @@ namespace OpenSim.Region.Physics.OdePlugin
45 public class ODERayCastRequestManager 45 public class ODERayCastRequestManager
46 { 46 {
47 /// <summary> 47 /// <summary>
48 /// Pending Raycast Requests 48 /// Pending raycast requests
49 /// </summary> 49 /// </summary>
50 protected List<ODERayCastRequest> m_PendingRequests = new List<ODERayCastRequest>(); 50 protected List<ODERayCastRequest> m_PendingRequests = new List<ODERayCastRequest>();
51 51
52 /// <summary> 52 /// <summary>
53 /// Pending ray requests
54 /// </summary>
55 protected List<ODERayRequest> m_PendingRayRequests = new List<ODERayRequest>();
56
57 /// <summary>
53 /// Scene that created this object. 58 /// Scene that created this object.
54 /// </summary> 59 /// </summary>
55 private OdeScene m_scene; 60 private OdeScene m_scene;
@@ -96,6 +101,29 @@ namespace OpenSim.Region.Physics.OdePlugin
96 } 101 }
97 102
98 /// <summary> 103 /// <summary>
104 /// Queues a raycast
105 /// </summary>
106 /// <param name="position">Origin of Ray</param>
107 /// <param name="direction">Ray normal</param>
108 /// <param name="length">Ray length</param>
109 /// <param name="count"></param>
110 /// <param name="retMethod">Return method to send the results</param>
111 public void QueueRequest(Vector3 position, Vector3 direction, float length, int count, RayCallback retMethod)
112 {
113 lock (m_PendingRequests)
114 {
115 ODERayRequest req = new ODERayRequest();
116 req.callbackMethod = retMethod;
117 req.length = length;
118 req.Normal = direction;
119 req.Origin = position;
120 req.Count = count;
121
122 m_PendingRayRequests.Add(req);
123 }
124 }
125
126 /// <summary>
99 /// Process all queued raycast requests 127 /// Process all queued raycast requests
100 /// </summary> 128 /// </summary>
101 /// <returns>Time in MS the raycasts took to process.</returns> 129 /// <returns>Time in MS the raycasts took to process.</returns>
@@ -119,15 +147,23 @@ namespace OpenSim.Region.Physics.OdePlugin
119 //Fail silently 147 //Fail silently
120 } 148 }
121 } 149 }
122 /* 150
123 foreach (ODERayCastRequest req in m_PendingRequests) 151 m_PendingRequests.Clear();
152 }
153 }
154
155 lock (m_PendingRayRequests)
156 {
157 if (m_PendingRayRequests.Count > 0)
158 {
159 ODERayRequest[] reqs = m_PendingRayRequests.ToArray();
160 for (int i = 0; i < reqs.Length; i++)
124 { 161 {
125 if (req.callbackMethod != null) // quick optimization here, don't raycast 162 if (reqs[i].callbackMethod != null) // quick optimization here, don't raycast
126 RayCast(req); // if there isn't anyone to send results to 163 RayCast(reqs[i]); // if there isn't anyone to send results
127
128 } 164 }
129 */ 165
130 m_PendingRequests.Clear(); 166 m_PendingRayRequests.Clear();
131 } 167 }
132 } 168 }
133 169
@@ -153,7 +189,6 @@ namespace OpenSim.Region.Physics.OdePlugin
153 // Remove Ray 189 // Remove Ray
154 d.GeomDestroy(ray); 190 d.GeomDestroy(ray);
155 191
156
157 // Define default results 192 // Define default results
158 bool hitYN = false; 193 bool hitYN = false;
159 uint hitConsumerID = 0; 194 uint hitConsumerID = 0;
@@ -184,6 +219,31 @@ namespace OpenSim.Region.Physics.OdePlugin
184 req.callbackMethod(hitYN, closestcontact, hitConsumerID, distance, snormal); 219 req.callbackMethod(hitYN, closestcontact, hitConsumerID, distance, snormal);
185 } 220 }
186 221
222 /// <summary>
223 /// Method that actually initiates the raycast
224 /// </summary>
225 /// <param name="req"></param>
226 private void RayCast(ODERayRequest req)
227 {
228 // Create the ray
229 IntPtr ray = d.CreateRay(m_scene.space, req.length);
230 d.GeomRaySet(ray, req.Origin.X, req.Origin.Y, req.Origin.Z, req.Normal.X, req.Normal.Y, req.Normal.Z);
231
232 // Collide test
233 d.SpaceCollide2(m_scene.space, ray, IntPtr.Zero, nearCallback);
234
235 // Remove Ray
236 d.GeomDestroy(ray);
237
238 // Find closest contact and object.
239 lock (m_contactResults)
240 {
241 // Return results
242 if (req.callbackMethod != null)
243 req.callbackMethod(m_contactResults);
244 }
245 }
246
187 // This is the standard Near. Uses space AABBs to speed up detection. 247 // This is the standard Near. Uses space AABBs to speed up detection.
188 private void near(IntPtr space, IntPtr g1, IntPtr g2) 248 private void near(IntPtr space, IntPtr g1, IntPtr g2)
189 { 249 {
@@ -349,10 +409,7 @@ namespace OpenSim.Region.Physics.OdePlugin
349 m_contactResults.Add(collisionresult); 409 m_contactResults.Add(collisionresult);
350 } 410 }
351 } 411 }
352
353
354 } 412 }
355
356 } 413 }
357 414
358 /// <summary> 415 /// <summary>
@@ -372,11 +429,12 @@ namespace OpenSim.Region.Physics.OdePlugin
372 public RaycastCallback callbackMethod; 429 public RaycastCallback callbackMethod;
373 } 430 }
374 431
375 public struct ContactResult 432 public struct ODERayRequest
376 { 433 {
377 public Vector3 Pos; 434 public Vector3 Origin;
378 public float Depth;
379 public uint ConsumerID;
380 public Vector3 Normal; 435 public Vector3 Normal;
436 public int Count;
437 public float length;
438 public RayCallback callbackMethod;
381 } 439 }
382} 440} \ No newline at end of file
diff --git a/OpenSim/Region/Physics/OdePlugin/OdeScene.cs b/OpenSim/Region/Physics/OdePlugin/OdeScene.cs
index 88902b0..6e603e8 100644
--- a/OpenSim/Region/Physics/OdePlugin/OdeScene.cs
+++ b/OpenSim/Region/Physics/OdePlugin/OdeScene.cs
@@ -26,7 +26,7 @@
26 */ 26 */
27 27
28//#define USE_DRAWSTUFF 28//#define USE_DRAWSTUFF
29#define SPAM 29//#define SPAM
30 30
31using System; 31using System;
32using System.Collections.Generic; 32using System.Collections.Generic;
@@ -100,7 +100,7 @@ namespace OpenSim.Region.Physics.OdePlugin
100 Rubber = 6 100 Rubber = 6
101 } 101 }
102 102
103 public sealed class OdeScene : PhysicsScene 103 public class OdeScene : PhysicsScene
104 { 104 {
105 private readonly ILog m_log; 105 private readonly ILog m_log;
106 // private Dictionary<string, sCollisionData> m_storedCollisions = new Dictionary<string, sCollisionData>(); 106 // private Dictionary<string, sCollisionData> m_storedCollisions = new Dictionary<string, sCollisionData>();
@@ -198,7 +198,12 @@ namespace OpenSim.Region.Physics.OdePlugin
198 private readonly List<OdePrim> _taintedPrimL = new List<OdePrim>(); 198 private readonly List<OdePrim> _taintedPrimL = new List<OdePrim>();
199 private readonly HashSet<OdeCharacter> _taintedActors = new HashSet<OdeCharacter>(); 199 private readonly HashSet<OdeCharacter> _taintedActors = new HashSet<OdeCharacter>();
200 private readonly List<d.ContactGeom> _perloopContact = new List<d.ContactGeom>(); 200 private readonly List<d.ContactGeom> _perloopContact = new List<d.ContactGeom>();
201
202 /// <summary>
203 /// A list of actors that should receive collision events.
204 /// </summary>
201 private readonly List<PhysicsActor> _collisionEventPrim = new List<PhysicsActor>(); 205 private readonly List<PhysicsActor> _collisionEventPrim = new List<PhysicsActor>();
206
202 private readonly HashSet<OdeCharacter> _badCharacter = new HashSet<OdeCharacter>(); 207 private readonly HashSet<OdeCharacter> _badCharacter = new HashSet<OdeCharacter>();
203 public Dictionary<IntPtr, String> geom_name_map = new Dictionary<IntPtr, String>(); 208 public Dictionary<IntPtr, String> geom_name_map = new Dictionary<IntPtr, String>();
204 public Dictionary<IntPtr, PhysicsActor> actor_name_map = new Dictionary<IntPtr, PhysicsActor>(); 209 public Dictionary<IntPtr, PhysicsActor> actor_name_map = new Dictionary<IntPtr, PhysicsActor>();
@@ -299,7 +304,6 @@ namespace OpenSim.Region.Physics.OdePlugin
299 // Create the world and the first space 304 // Create the world and the first space
300 world = d.WorldCreate(); 305 world = d.WorldCreate();
301 space = d.HashSpaceCreate(IntPtr.Zero); 306 space = d.HashSpaceCreate(IntPtr.Zero);
302
303 307
304 contactgroup = d.JointGroupCreate(0); 308 contactgroup = d.JointGroupCreate(0);
305 //contactgroup 309 //contactgroup
@@ -952,7 +956,6 @@ namespace OpenSim.Region.Physics.OdePlugin
952 character.SetPidStatus(true); 956 character.SetPidStatus(true);
953 } 957 }
954 } 958 }
955
956 959
957 if (p1.PhysicsActorType == (int) ActorTypes.Agent) 960 if (p1.PhysicsActorType == (int) ActorTypes.Agent)
958 { 961 {
@@ -1053,9 +1056,7 @@ namespace OpenSim.Region.Physics.OdePlugin
1053 { 1056 {
1054 joint = d.JointCreateContact(world, contactgroup, ref m_materialContacts[material, movintYN]); 1057 joint = d.JointCreateContact(world, contactgroup, ref m_materialContacts[material, movintYN]);
1055 m_global_contactcount++; 1058 m_global_contactcount++;
1056
1057 } 1059 }
1058
1059 } 1060 }
1060 else 1061 else
1061 { 1062 {
@@ -1078,7 +1079,6 @@ namespace OpenSim.Region.Physics.OdePlugin
1078 { 1079 {
1079 joint = d.JointCreateContact(world, contactgroup, ref m_materialContacts[material, movintYN]); 1080 joint = d.JointCreateContact(world, contactgroup, ref m_materialContacts[material, movintYN]);
1080 m_global_contactcount++; 1081 m_global_contactcount++;
1081
1082 } 1082 }
1083 } 1083 }
1084 } 1084 }
@@ -1290,6 +1290,7 @@ namespace OpenSim.Region.Physics.OdePlugin
1290 1290
1291 //returncollisions = true; 1291 //returncollisions = true;
1292 break; 1292 break;
1293
1293 case ActorTypes.Prim: 1294 case ActorTypes.Prim:
1294 if (p1 is OdePrim) 1295 if (p1 is OdePrim)
1295 { 1296 {
@@ -1317,6 +1318,7 @@ namespace OpenSim.Region.Physics.OdePlugin
1317 1318
1318 cc2.AddCollisionEvent(obj2LocalID, contact); 1319 cc2.AddCollisionEvent(obj2LocalID, contact);
1319 break; 1320 break;
1321
1320 case ActorTypes.Prim: 1322 case ActorTypes.Prim:
1321 1323
1322 if (p2 is OdePrim) 1324 if (p2 is OdePrim)
@@ -1421,18 +1423,18 @@ namespace OpenSim.Region.Physics.OdePlugin
1421 1423
1422 public int TriCallback(IntPtr trimesh, IntPtr refObject, int triangleIndex) 1424 public int TriCallback(IntPtr trimesh, IntPtr refObject, int triangleIndex)
1423 { 1425 {
1424 String name1 = null; 1426// String name1 = null;
1425 String name2 = null; 1427// String name2 = null;
1426 1428//
1427 if (!geom_name_map.TryGetValue(trimesh, out name1)) 1429// if (!geom_name_map.TryGetValue(trimesh, out name1))
1428 { 1430// {
1429 name1 = "null"; 1431// name1 = "null";
1430 } 1432// }
1431 1433//
1432 if (!geom_name_map.TryGetValue(refObject, out name2)) 1434// if (!geom_name_map.TryGetValue(refObject, out name2))
1433 { 1435// {
1434 name2 = "null"; 1436// name2 = "null";
1435 } 1437// }
1436 1438
1437 // m_log.InfoFormat("TriCallback: A collision was detected between {1} and {2}. Index was {3}", 0, name1, name2, triangleIndex); 1439 // m_log.InfoFormat("TriCallback: A collision was detected between {1} and {2}. Index was {3}", 0, name1, name2, triangleIndex);
1438 1440
@@ -1604,7 +1606,11 @@ namespace OpenSim.Region.Physics.OdePlugin
1604 } 1606 }
1605// End recovered. Kitto Flora 1607// End recovered. Kitto Flora
1606 1608
1607 public void addCollisionEventReporting(PhysicsActor obj) 1609 /// <summary>
1610 /// Add actor to the list that should receive collision events in the simulate loop.
1611 /// </summary>
1612 /// <param name="obj"></param>
1613 public void AddCollisionEventReporting(PhysicsActor obj)
1608 { 1614 {
1609 lock (_collisionEventPrim) 1615 lock (_collisionEventPrim)
1610 { 1616 {
@@ -1613,7 +1619,11 @@ namespace OpenSim.Region.Physics.OdePlugin
1613 } 1619 }
1614 } 1620 }
1615 1621
1616 public void remCollisionEventReporting(PhysicsActor obj) 1622 /// <summary>
1623 /// Remove actor from the list that should receive collision events in the simulate loop.
1624 /// </summary>
1625 /// <param name="obj"></param>
1626 public void RemoveCollisionEventReporting(PhysicsActor obj)
1617 { 1627 {
1618 lock (_collisionEventPrim) 1628 lock (_collisionEventPrim)
1619 { 1629 {
@@ -1677,7 +1687,7 @@ namespace OpenSim.Region.Physics.OdePlugin
1677 } 1687 }
1678 1688
1679 private PhysicsActor AddPrim(String name, Vector3 position, Vector3 size, Quaternion rotation, 1689 private PhysicsActor AddPrim(String name, Vector3 position, Vector3 size, Quaternion rotation,
1680 IMesh mesh, PrimitiveBaseShape pbs, bool isphysical) 1690 PrimitiveBaseShape pbs, bool isphysical, uint localID)
1681 { 1691 {
1682 Vector3 pos = position; 1692 Vector3 pos = position;
1683 Vector3 siz = size; 1693 Vector3 siz = size;
@@ -1686,12 +1696,12 @@ namespace OpenSim.Region.Physics.OdePlugin
1686 OdePrim newPrim; 1696 OdePrim newPrim;
1687 lock (OdeLock) 1697 lock (OdeLock)
1688 { 1698 {
1689 newPrim = new OdePrim(name, this, pos, siz, rot, mesh, pbs, isphysical, ode); 1699 newPrim = new OdePrim(name, this, pos, siz, rot, pbs, isphysical, ode);
1690 1700
1691 lock (_prims) 1701 lock (_prims)
1692 _prims.Add(newPrim); 1702 _prims.Add(newPrim);
1693 } 1703 }
1694 1704 newPrim.LocalID = localID;
1695 return newPrim; 1705 return newPrim;
1696 } 1706 }
1697 1707
@@ -1714,27 +1724,7 @@ namespace OpenSim.Region.Physics.OdePlugin
1714 m_log.DebugFormat("[PHYSICS]: Adding physics actor to {0}", primName); 1724 m_log.DebugFormat("[PHYSICS]: Adding physics actor to {0}", primName);
1715#endif 1725#endif
1716 1726
1717 PhysicsActor result; 1727 return AddPrim(primName, position, size, rotation, pbs, isPhysical, localid);
1718 IMesh mesh = null;
1719
1720 if (needsMeshing(pbs))
1721 {
1722 try
1723 {
1724 mesh = mesher.CreateMesh(primName, pbs, size, 32f, isPhysical);
1725 }
1726 catch(Exception e)
1727 {
1728 m_log.ErrorFormat("[PHYSICS]: Exception while meshing prim {0}.", primName);
1729 m_log.Debug(e.ToString());
1730 mesh = null;
1731 return null;
1732 }
1733 }
1734
1735 result = AddPrim(primName, position, size, rotation, mesh, pbs, isPhysical);
1736
1737 return result;
1738 } 1728 }
1739 1729
1740 public override float TimeDilation 1730 public override float TimeDilation
@@ -2104,6 +2094,8 @@ namespace OpenSim.Region.Physics.OdePlugin
2104 2094
2105 public override void RemovePrim(PhysicsActor prim) 2095 public override void RemovePrim(PhysicsActor prim)
2106 { 2096 {
2097 // As with all ODE physics operations, we don't remove the prim immediately but signal that it should be
2098 // removed in the next physics simulate pass.
2107 if (prim is OdePrim) 2099 if (prim is OdePrim)
2108 { 2100 {
2109 lock (OdeLock) 2101 lock (OdeLock)
@@ -2120,6 +2112,9 @@ namespace OpenSim.Region.Physics.OdePlugin
2120 /// <summary> 2112 /// <summary>
2121 /// This is called from within simulate but outside the locked portion 2113 /// This is called from within simulate but outside the locked portion
2122 /// We need to do our own locking here 2114 /// We need to do our own locking here
2115 /// (Note: As of 20110801 this no longer appears to be true - this is being called within lock (odeLock) in
2116 /// Simulate() -- justincc).
2117 ///
2123 /// Essentially, we need to remove the prim from our space segment, whatever segment it's in. 2118 /// Essentially, we need to remove the prim from our space segment, whatever segment it's in.
2124 /// 2119 ///
2125 /// If there are no more prim in the segment, we need to empty (spacedestroy)the segment and reclaim memory 2120 /// If there are no more prim in the segment, we need to empty (spacedestroy)the segment and reclaim memory
@@ -2131,7 +2126,7 @@ namespace OpenSim.Region.Physics.OdePlugin
2131//Console.WriteLine("RemovePrimThreadLocked " + prim.m_primName); 2126//Console.WriteLine("RemovePrimThreadLocked " + prim.m_primName);
2132 lock (prim) 2127 lock (prim)
2133 { 2128 {
2134 remCollisionEventReporting(prim); 2129 RemoveCollisionEventReporting(prim);
2135 lock (ode) 2130 lock (ode)
2136 { 2131 {
2137 if (prim.prim_geom != IntPtr.Zero) 2132 if (prim.prim_geom != IntPtr.Zero)
@@ -2176,24 +2171,12 @@ namespace OpenSim.Region.Physics.OdePlugin
2176 //} 2171 //}
2177 //} 2172 //}
2178 //m_log.Warn(prim.prim_geom); 2173 //m_log.Warn(prim.prim_geom);
2179 try 2174
2180 { 2175 if (!prim.RemoveGeom())
2181 if (prim.prim_geom != IntPtr.Zero) 2176 m_log.Warn("[PHYSICS]: Unable to remove prim from physics scene");
2182 { 2177
2183 d.GeomDestroy(prim.prim_geom);
2184 prim.prim_geom = IntPtr.Zero;
2185 }
2186 else
2187 {
2188 m_log.Warn("[PHYSICS]: Unable to remove prim from physics scene");
2189 }
2190 }
2191 catch (AccessViolationException)
2192 {
2193 m_log.Info("[PHYSICS]: Couldn't remove prim from physics scene, it was already be removed.");
2194 }
2195 lock (_prims) 2178 lock (_prims)
2196 _prims.Remove(prim); 2179 _prims.Remove(prim);
2197 2180
2198 //If there are no more geometries in the sub-space, we don't need it in the main space anymore 2181 //If there are no more geometries in the sub-space, we don't need it in the main space anymore
2199 //if (d.SpaceGetNumGeoms(prim.m_targetSpace) == 0) 2182 //if (d.SpaceGetNumGeoms(prim.m_targetSpace) == 0)
@@ -2584,7 +2567,9 @@ namespace OpenSim.Region.Physics.OdePlugin
2584 { 2567 {
2585 if (!(_taintedPrimH.Contains(taintedprim))) 2568 if (!(_taintedPrimH.Contains(taintedprim)))
2586 { 2569 {
2587//Console.WriteLine("AddPhysicsActorTaint to " + taintedprim.m_primName); 2570#if SPAM
2571Console.WriteLine("AddPhysicsActorTaint to " + taintedprim.Name);
2572#endif
2588 _taintedPrimH.Add(taintedprim); // HashSet for searching 2573 _taintedPrimH.Add(taintedprim); // HashSet for searching
2589 _taintedPrimL.Add(taintedprim); // List for ordered readout 2574 _taintedPrimL.Add(taintedprim); // List for ordered readout
2590 } 2575 }
@@ -2684,320 +2669,148 @@ namespace OpenSim.Region.Physics.OdePlugin
2684 //if (!ode.lockquery()) 2669 //if (!ode.lockquery())
2685 //{ 2670 //{
2686 // ode.dlock(world); 2671 // ode.dlock(world);
2687 try
2688 {
2689 // Insert, remove Characters
2690 bool processedtaints = false;
2691 2672
2692 lock (_taintedActors) 2673 try
2693 { 2674 {
2694 if (_taintedActors.Count > 0) 2675 // Insert, remove Characters
2695 { 2676 bool processedtaints = false;
2696 foreach (OdeCharacter character in _taintedActors)
2697 {
2698 character.ProcessTaints(timeStep);
2699 2677
2700 processedtaints = true; 2678 lock (_taintedActors)
2701 //character.m_collisionscore = 0; 2679 {
2702 } 2680 if (_taintedActors.Count > 0)
2681 {
2682 foreach (OdeCharacter character in _taintedActors)
2683 {
2684 character.ProcessTaints(timeStep);
2703 2685
2704 if (processedtaints) 2686 processedtaints = true;
2705 _taintedActors.Clear(); 2687 //character.m_collisionscore = 0;
2706 }
2707 } 2688 }
2708 2689
2709 // Modify other objects in the scene. 2690 if (processedtaints)
2710 processedtaints = false; 2691 _taintedActors.Clear();
2692 }
2693 }
2694
2695 // Modify other objects in the scene.
2696 processedtaints = false;
2711 2697
2712 lock (_taintedPrimLock) 2698 lock (_taintedPrimLock)
2699 {
2700 foreach (OdePrim prim in _taintedPrimL)
2701 {
2702 if (prim.m_taintremove)
2713 { 2703 {
2714 foreach (OdePrim prim in _taintedPrimL) 2704// Console.WriteLine("Simulate calls RemovePrimThreadLocked for {0}", prim.Name);
2715 { 2705 RemovePrimThreadLocked(prim);
2716 if (prim.m_taintremove) 2706 }
2717 { 2707 else
2718 //Console.WriteLine("Simulate calls RemovePrimThreadLocked"); 2708 {
2719 RemovePrimThreadLocked(prim); 2709// Console.WriteLine("Simulate calls ProcessTaints for {0}", prim.Name);
2720 } 2710 prim.ProcessTaints(timeStep);
2721 else 2711 }
2722 {
2723 //Console.WriteLine("Simulate calls ProcessTaints");
2724 prim.ProcessTaints(timeStep);
2725 }
2726 processedtaints = true;
2727 prim.m_collisionscore = 0;
2728
2729 // This loop can block up the Heartbeat for a very long time on large regions.
2730 // We need to let the Watchdog know that the Heartbeat is not dead
2731 // NOTE: This is currently commented out, but if things like OAR loading are
2732 // timing the heartbeat out we will need to uncomment it
2733 //Watchdog.UpdateThread();
2734 }
2735 2712
2736 if (SupportsNINJAJoints) 2713 processedtaints = true;
2737 { 2714 prim.m_collisionscore = 0;
2738 // Create pending joints, if possible
2739 2715
2740 // joints can only be processed after ALL bodies are processed (and exist in ODE), since creating 2716 // This loop can block up the Heartbeat for a very long time on large regions.
2741 // a joint requires specifying the body id of both involved bodies 2717 // We need to let the Watchdog know that the Heartbeat is not dead
2742 if (pendingJoints.Count > 0) 2718 // NOTE: This is currently commented out, but if things like OAR loading are
2743 { 2719 // timing the heartbeat out we will need to uncomment it
2744 List<PhysicsJoint> successfullyProcessedPendingJoints = new List<PhysicsJoint>(); 2720 //Watchdog.UpdateThread();
2745 //DoJointErrorMessage(joints_connecting_actor, "taint: " + pendingJoints.Count + " pending joints"); 2721 }
2746 foreach (PhysicsJoint joint in pendingJoints) 2722
2747 { 2723 if (SupportsNINJAJoints)
2748 //DoJointErrorMessage(joint, "taint: time to create joint with parms: " + joint.RawParams); 2724 SimulatePendingNINJAJoints();
2749 string[] jointParams = joint.RawParams.Split(" ".ToCharArray(), System.StringSplitOptions.RemoveEmptyEntries);
2750 List<IntPtr> jointBodies = new List<IntPtr>();
2751 bool allJointBodiesAreReady = true;
2752 foreach (string jointParam in jointParams)
2753 {
2754 if (jointParam == "NULL")
2755 {
2756 //DoJointErrorMessage(joint, "attaching NULL joint to world");
2757 jointBodies.Add(IntPtr.Zero);
2758 }
2759 else
2760 {
2761 //DoJointErrorMessage(joint, "looking for prim name: " + jointParam);
2762 bool foundPrim = false;
2763 lock (_prims)
2764 {
2765 foreach (OdePrim prim in _prims) // FIXME: inefficient
2766 {
2767 if (prim.SOPName == jointParam)
2768 {
2769 //DoJointErrorMessage(joint, "found for prim name: " + jointParam);
2770 if (prim.IsPhysical && prim.Body != IntPtr.Zero)
2771 {
2772 jointBodies.Add(prim.Body);
2773 foundPrim = true;
2774 break;
2775 }
2776 else
2777 {
2778 DoJointErrorMessage(joint, "prim name " + jointParam +
2779 " exists but is not (yet) physical; deferring joint creation. " +
2780 "IsPhysical property is " + prim.IsPhysical +
2781 " and body is " + prim.Body);
2782 foundPrim = false;
2783 break;
2784 }
2785 }
2786 }
2787 }
2788 if (foundPrim)
2789 {
2790 // all is fine
2791 }
2792 else
2793 {
2794 allJointBodiesAreReady = false;
2795 break;
2796 }
2797 }
2798 }
2799 if (allJointBodiesAreReady)
2800 {
2801 //DoJointErrorMessage(joint, "allJointBodiesAreReady for " + joint.ObjectNameInScene + " with parms " + joint.RawParams);
2802 if (jointBodies[0] == jointBodies[1])
2803 {
2804 DoJointErrorMessage(joint, "ERROR: joint cannot be created; the joint bodies are the same, body1==body2. Raw body is " + jointBodies[0] + ". raw parms: " + joint.RawParams);
2805 }
2806 else
2807 {
2808 switch (joint.Type)
2809 {
2810 case PhysicsJointType.Ball:
2811 {
2812 IntPtr odeJoint;
2813 //DoJointErrorMessage(joint, "ODE creating ball joint ");
2814 odeJoint = d.JointCreateBall(world, IntPtr.Zero);
2815 //DoJointErrorMessage(joint, "ODE attaching ball joint: " + odeJoint + " with b1:" + jointBodies[0] + " b2:" + jointBodies[1]);
2816 d.JointAttach(odeJoint, jointBodies[0], jointBodies[1]);
2817 //DoJointErrorMessage(joint, "ODE setting ball anchor: " + odeJoint + " to vec:" + joint.Position);
2818 d.JointSetBallAnchor(odeJoint,
2819 joint.Position.X,
2820 joint.Position.Y,
2821 joint.Position.Z);
2822 //DoJointErrorMessage(joint, "ODE joint setting OK");
2823 //DoJointErrorMessage(joint, "The ball joint's bodies are here: b0: ");
2824 //DoJointErrorMessage(joint, "" + (jointBodies[0] != IntPtr.Zero ? "" + d.BodyGetPosition(jointBodies[0]) : "fixed environment"));
2825 //DoJointErrorMessage(joint, "The ball joint's bodies are here: b1: ");
2826 //DoJointErrorMessage(joint, "" + (jointBodies[1] != IntPtr.Zero ? "" + d.BodyGetPosition(jointBodies[1]) : "fixed environment"));
2827
2828 if (joint is OdePhysicsJoint)
2829 {
2830 ((OdePhysicsJoint)joint).jointID = odeJoint;
2831 }
2832 else
2833 {
2834 DoJointErrorMessage(joint, "WARNING: non-ode joint in ODE!");
2835 }
2836 }
2837 break;
2838 case PhysicsJointType.Hinge:
2839 {
2840 IntPtr odeJoint;
2841 //DoJointErrorMessage(joint, "ODE creating hinge joint ");
2842 odeJoint = d.JointCreateHinge(world, IntPtr.Zero);
2843 //DoJointErrorMessage(joint, "ODE attaching hinge joint: " + odeJoint + " with b1:" + jointBodies[0] + " b2:" + jointBodies[1]);
2844 d.JointAttach(odeJoint, jointBodies[0], jointBodies[1]);
2845 //DoJointErrorMessage(joint, "ODE setting hinge anchor: " + odeJoint + " to vec:" + joint.Position);
2846 d.JointSetHingeAnchor(odeJoint,
2847 joint.Position.X,
2848 joint.Position.Y,
2849 joint.Position.Z);
2850 // We use the orientation of the x-axis of the joint's coordinate frame
2851 // as the axis for the hinge.
2852
2853 // Therefore, we must get the joint's coordinate frame based on the
2854 // joint.Rotation field, which originates from the orientation of the
2855 // joint's proxy object in the scene.
2856
2857 // The joint's coordinate frame is defined as the transformation matrix
2858 // that converts a vector from joint-local coordinates into world coordinates.
2859 // World coordinates are defined as the XYZ coordinate system of the sim,
2860 // as shown in the top status-bar of the viewer.
2861
2862 // Once we have the joint's coordinate frame, we extract its X axis (AtAxis)
2863 // and use that as the hinge axis.
2864
2865 //joint.Rotation.Normalize();
2866 Matrix4 proxyFrame = Matrix4.CreateFromQuaternion(joint.Rotation);
2867
2868 // Now extract the X axis of the joint's coordinate frame.
2869
2870 // Do not try to use proxyFrame.AtAxis or you will become mired in the
2871 // tar pit of transposed, inverted, and generally messed-up orientations.
2872 // (In other words, Matrix4.AtAxis() is borked.)
2873 // Vector3 jointAxis = proxyFrame.AtAxis; <--- this path leadeth to madness
2874
2875 // Instead, compute the X axis of the coordinate frame by transforming
2876 // the (1,0,0) vector. At least that works.
2877
2878 //m_log.Debug("PHY: making axis: complete matrix is " + proxyFrame);
2879 Vector3 jointAxis = Vector3.Transform(Vector3.UnitX, proxyFrame);
2880 //m_log.Debug("PHY: making axis: hinge joint axis is " + jointAxis);
2881 //DoJointErrorMessage(joint, "ODE setting hinge axis: " + odeJoint + " to vec:" + jointAxis);
2882 d.JointSetHingeAxis(odeJoint,
2883 jointAxis.X,
2884 jointAxis.Y,
2885 jointAxis.Z);
2886 //d.JointSetHingeParam(odeJoint, (int)dParam.CFM, 0.1f);
2887 if (joint is OdePhysicsJoint)
2888 {
2889 ((OdePhysicsJoint)joint).jointID = odeJoint;
2890 }
2891 else
2892 {
2893 DoJointErrorMessage(joint, "WARNING: non-ode joint in ODE!");
2894 }
2895 }
2896 break;
2897 }
2898 successfullyProcessedPendingJoints.Add(joint);
2899 }
2900 }
2901 else
2902 {
2903 DoJointErrorMessage(joint, "joint could not yet be created; still pending");
2904 }
2905 }
2906 foreach (PhysicsJoint successfullyProcessedJoint in successfullyProcessedPendingJoints)
2907 {
2908 //DoJointErrorMessage(successfullyProcessedJoint, "finalizing succesfully procsssed joint " + successfullyProcessedJoint.ObjectNameInScene + " parms " + successfullyProcessedJoint.RawParams);
2909 //DoJointErrorMessage(successfullyProcessedJoint, "removing from pending");
2910 InternalRemovePendingJoint(successfullyProcessedJoint);
2911 //DoJointErrorMessage(successfullyProcessedJoint, "adding to active");
2912 InternalAddActiveJoint(successfullyProcessedJoint);
2913 //DoJointErrorMessage(successfullyProcessedJoint, "done");
2914 }
2915 }
2916 }
2917 2725
2918 if (processedtaints) 2726 if (processedtaints)
2727 {
2919//Console.WriteLine("Simulate calls Clear of _taintedPrim list"); 2728//Console.WriteLine("Simulate calls Clear of _taintedPrim list");
2920 _taintedPrimH.Clear(); 2729 _taintedPrimH.Clear();
2921 _taintedPrimL.Clear(); 2730 _taintedPrimL.Clear();
2922 } 2731 }
2732 }
2923 2733
2924 // Move characters 2734 // Move characters
2925 lock (_characters) 2735 lock (_characters)
2736 {
2737 List<OdeCharacter> defects = new List<OdeCharacter>();
2738 foreach (OdeCharacter actor in _characters)
2739 {
2740 if (actor != null)
2741 actor.Move(timeStep, defects);
2742 }
2743 if (0 != defects.Count)
2744 {
2745 foreach (OdeCharacter defect in defects)
2926 { 2746 {
2927 List<OdeCharacter> defects = new List<OdeCharacter>(); 2747 RemoveCharacter(defect);
2928 foreach (OdeCharacter actor in _characters)
2929 {
2930 if (actor != null)
2931 actor.Move(timeStep, defects);
2932 }
2933 if (0 != defects.Count)
2934 {
2935 foreach (OdeCharacter defect in defects)
2936 {
2937 RemoveCharacter(defect);
2938 }
2939 }
2940 } 2748 }
2749 }
2750 }
2941 2751
2942 // Move other active objects 2752 // Move other active objects
2943 lock (_activeprims) 2753 lock (_activeprims)
2944 { 2754 {
2945 foreach (OdePrim prim in _activeprims) 2755 foreach (OdePrim prim in _activeprims)
2946 { 2756 {
2947 prim.m_collisionscore = 0; 2757 prim.m_collisionscore = 0;
2948 prim.Move(timeStep); 2758 prim.Move(timeStep);
2949 } 2759 }
2950 } 2760 }
2951 2761
2952 //if ((framecount % m_randomizeWater) == 0) 2762 //if ((framecount % m_randomizeWater) == 0)
2953 // randomizeWater(waterlevel); 2763 // randomizeWater(waterlevel);
2954 2764
2955 //int RayCastTimeMS = m_rayCastManager.ProcessQueuedRequests(); 2765 //int RayCastTimeMS = m_rayCastManager.ProcessQueuedRequests();
2956 m_rayCastManager.ProcessQueuedRequests(); 2766 m_rayCastManager.ProcessQueuedRequests();
2767
2768 collision_optimized(timeStep);
2769
2770 lock (_collisionEventPrim)
2771 {
2772 foreach (PhysicsActor obj in _collisionEventPrim)
2773 {
2774 if (obj == null)
2775 continue;
2957 2776
2958 collision_optimized(timeStep); 2777// m_log.DebugFormat("[PHYSICS]: Assessing {0} for collision events", obj.SOPName);
2959 2778
2960 lock (_collisionEventPrim) 2779 switch ((ActorTypes)obj.PhysicsActorType)
2961 { 2780 {
2962 foreach (PhysicsActor obj in _collisionEventPrim) 2781 case ActorTypes.Agent:
2963 { 2782 OdeCharacter cobj = (OdeCharacter)obj;
2964 if (obj == null) 2783 cobj.AddCollisionFrameTime(100);
2965 continue; 2784 cobj.SendCollisions();
2785 break;
2966 2786
2967 switch ((ActorTypes)obj.PhysicsActorType) 2787 case ActorTypes.Prim:
2968 { 2788 OdePrim pobj = (OdePrim)obj;
2969 case ActorTypes.Agent: 2789 pobj.SendCollisions();
2970 OdeCharacter cobj = (OdeCharacter)obj; 2790 break;
2971 cobj.AddCollisionFrameTime(100);
2972 cobj.SendCollisions();
2973 break;
2974 case ActorTypes.Prim:
2975 OdePrim pobj = (OdePrim)obj;
2976 pobj.SendCollisions();
2977 break;
2978 }
2979 }
2980 } 2791 }
2792 }
2793 }
2981 2794
2982 //if (m_global_contactcount > 5) 2795 //if (m_global_contactcount > 5)
2983 //{ 2796 //{
2984 // m_log.DebugFormat("[PHYSICS]: Contacts:{0}", m_global_contactcount); 2797 // m_log.DebugFormat("[PHYSICS]: Contacts:{0}", m_global_contactcount);
2985 //} 2798 //}
2986 2799
2987 m_global_contactcount = 0; 2800 m_global_contactcount = 0;
2988 2801
2989 d.WorldQuickStep(world, ODE_STEPSIZE); 2802 d.WorldQuickStep(world, ODE_STEPSIZE);
2990 d.JointGroupEmpty(contactgroup); 2803 d.JointGroupEmpty(contactgroup);
2991 //ode.dunlock(world); 2804 //ode.dunlock(world);
2992 } 2805 }
2993 catch (Exception e) 2806 catch (Exception e)
2994 { 2807 {
2995 m_log.ErrorFormat("[PHYSICS]: {0}, {1}, {2}", e.Message, e.TargetSite, e); 2808 m_log.ErrorFormat("[PHYSICS]: {0}, {1}, {2}", e.Message, e.TargetSite, e);
2996 ode.dunlock(world); 2809 ode.dunlock(world);
2997 } 2810 }
2998 2811
2999 step_time -= ODE_STEPSIZE; 2812 step_time -= ODE_STEPSIZE;
3000 i++; 2813 i++;
3001 //} 2814 //}
3002 //else 2815 //else
3003 //{ 2816 //{
@@ -3014,6 +2827,7 @@ namespace OpenSim.Region.Physics.OdePlugin
3014 { 2827 {
3015 if (actor.bad) 2828 if (actor.bad)
3016 m_log.WarnFormat("[PHYSICS]: BAD Actor {0} in _characters list was not removed?", actor.m_uuid); 2829 m_log.WarnFormat("[PHYSICS]: BAD Actor {0} in _characters list was not removed?", actor.m_uuid);
2830
3017 actor.UpdatePositionAndVelocity(); 2831 actor.UpdatePositionAndVelocity();
3018 } 2832 }
3019 } 2833 }
@@ -3027,6 +2841,7 @@ namespace OpenSim.Region.Physics.OdePlugin
3027 { 2841 {
3028 RemoveCharacter(chr); 2842 RemoveCharacter(chr);
3029 } 2843 }
2844
3030 _badCharacter.Clear(); 2845 _badCharacter.Clear();
3031 } 2846 }
3032 } 2847 }
@@ -3042,30 +2857,7 @@ namespace OpenSim.Region.Physics.OdePlugin
3042 actor.UpdatePositionAndVelocity(); 2857 actor.UpdatePositionAndVelocity();
3043 2858
3044 if (SupportsNINJAJoints) 2859 if (SupportsNINJAJoints)
3045 { 2860 SimulateActorPendingJoints(actor);
3046 // If an actor moved, move its joint proxy objects as well.
3047 // There seems to be an event PhysicsActor.OnPositionUpdate that could be used
3048 // for this purpose but it is never called! So we just do the joint
3049 // movement code here.
3050
3051 if (actor.SOPName != null &&
3052 joints_connecting_actor.ContainsKey(actor.SOPName) &&
3053 joints_connecting_actor[actor.SOPName] != null &&
3054 joints_connecting_actor[actor.SOPName].Count > 0)
3055 {
3056 foreach (PhysicsJoint affectedJoint in joints_connecting_actor[actor.SOPName])
3057 {
3058 if (affectedJoint.IsInPhysicsEngine)
3059 {
3060 DoJointMoved(affectedJoint);
3061 }
3062 else
3063 {
3064 DoJointErrorMessage(affectedJoint, "a body connected to a joint was moved, but the joint doesn't exist yet! this will lead to joint error. joint was: " + affectedJoint.ObjectNameInScene + " parms:" + affectedJoint.RawParams);
3065 }
3066 }
3067 }
3068 }
3069 } 2861 }
3070 } 2862 }
3071 } 2863 }
@@ -3076,7 +2868,7 @@ namespace OpenSim.Region.Physics.OdePlugin
3076 // Finished with all sim stepping. If requested, dump world state to file for debugging. 2868 // Finished with all sim stepping. If requested, dump world state to file for debugging.
3077 // TODO: This call to the export function is already inside lock (OdeLock) - but is an extra lock needed? 2869 // TODO: This call to the export function is already inside lock (OdeLock) - but is an extra lock needed?
3078 // TODO: This overwrites all dump files in-place. Should this be a growing logfile, or separate snapshots? 2870 // TODO: This overwrites all dump files in-place. Should this be a growing logfile, or separate snapshots?
3079 if (physics_logging && (physics_logging_interval>0) && (framecount % physics_logging_interval == 0)) 2871 if (physics_logging && (physics_logging_interval > 0) && (framecount % physics_logging_interval == 0))
3080 { 2872 {
3081 string fname = "state-" + world.ToString() + ".DIF"; // give each physics world a separate filename 2873 string fname = "state-" + world.ToString() + ".DIF"; // give each physics world a separate filename
3082 string prefix = "world" + world.ToString(); // prefix for variable names in exported .DIF file 2874 string prefix = "world" + world.ToString(); // prefix for variable names in exported .DIF file
@@ -3088,8 +2880,10 @@ namespace OpenSim.Region.Physics.OdePlugin
3088 fwriter.WriteLine(header); 2880 fwriter.WriteLine(header);
3089 fwriter.Close(); 2881 fwriter.Close();
3090 } 2882 }
2883
3091 d.WorldExportDIF(world, fname, physics_logging_append_existing_logfile, prefix); 2884 d.WorldExportDIF(world, fname, physics_logging_append_existing_logfile, prefix);
3092 } 2885 }
2886
3093 latertickcount = Util.EnvironmentTickCount() - tickCountFrameRun; 2887 latertickcount = Util.EnvironmentTickCount() - tickCountFrameRun;
3094 2888
3095 // OpenSimulator above does 10 fps. 10 fps = means that the main thread loop and physics 2889 // OpenSimulator above does 10 fps. 10 fps = means that the main thread loop and physics
@@ -3098,7 +2892,9 @@ namespace OpenSim.Region.Physics.OdePlugin
3098 // If Physics stalls, it takes longer which makes the tick count ms larger. 2892 // If Physics stalls, it takes longer which makes the tick count ms larger.
3099 2893
3100 if (latertickcount < 100) 2894 if (latertickcount < 100)
2895 {
3101 m_timeDilation = 1.0f; 2896 m_timeDilation = 1.0f;
2897 }
3102 else 2898 else
3103 { 2899 {
3104 m_timeDilation = 100f / latertickcount; 2900 m_timeDilation = 100f / latertickcount;
@@ -3111,6 +2907,229 @@ namespace OpenSim.Region.Physics.OdePlugin
3111 return fps; 2907 return fps;
3112 } 2908 }
3113 2909
2910 /// <summary>
2911 /// Simulate pending NINJA joints.
2912 /// </summary>
2913 /// <remarks>
2914 /// Called by the main Simulate() loop if NINJA joints are active. Should not be called from anywhere else.
2915 /// </remarks>
2916 protected void SimulatePendingNINJAJoints()
2917 {
2918 // Create pending joints, if possible
2919
2920 // joints can only be processed after ALL bodies are processed (and exist in ODE), since creating
2921 // a joint requires specifying the body id of both involved bodies
2922 if (pendingJoints.Count > 0)
2923 {
2924 List<PhysicsJoint> successfullyProcessedPendingJoints = new List<PhysicsJoint>();
2925 //DoJointErrorMessage(joints_connecting_actor, "taint: " + pendingJoints.Count + " pending joints");
2926 foreach (PhysicsJoint joint in pendingJoints)
2927 {
2928 //DoJointErrorMessage(joint, "taint: time to create joint with parms: " + joint.RawParams);
2929 string[] jointParams = joint.RawParams.Split(" ".ToCharArray(), System.StringSplitOptions.RemoveEmptyEntries);
2930 List<IntPtr> jointBodies = new List<IntPtr>();
2931 bool allJointBodiesAreReady = true;
2932 foreach (string jointParam in jointParams)
2933 {
2934 if (jointParam == "NULL")
2935 {
2936 //DoJointErrorMessage(joint, "attaching NULL joint to world");
2937 jointBodies.Add(IntPtr.Zero);
2938 }
2939 else
2940 {
2941 //DoJointErrorMessage(joint, "looking for prim name: " + jointParam);
2942 bool foundPrim = false;
2943 lock (_prims)
2944 {
2945 foreach (OdePrim prim in _prims) // FIXME: inefficient
2946 {
2947 if (prim.SOPName == jointParam)
2948 {
2949 //DoJointErrorMessage(joint, "found for prim name: " + jointParam);
2950 if (prim.IsPhysical && prim.Body != IntPtr.Zero)
2951 {
2952 jointBodies.Add(prim.Body);
2953 foundPrim = true;
2954 break;
2955 }
2956 else
2957 {
2958 DoJointErrorMessage(joint, "prim name " + jointParam +
2959 " exists but is not (yet) physical; deferring joint creation. " +
2960 "IsPhysical property is " + prim.IsPhysical +
2961 " and body is " + prim.Body);
2962 foundPrim = false;
2963 break;
2964 }
2965 }
2966 }
2967 }
2968 if (foundPrim)
2969 {
2970 // all is fine
2971 }
2972 else
2973 {
2974 allJointBodiesAreReady = false;
2975 break;
2976 }
2977 }
2978 }
2979
2980 if (allJointBodiesAreReady)
2981 {
2982 //DoJointErrorMessage(joint, "allJointBodiesAreReady for " + joint.ObjectNameInScene + " with parms " + joint.RawParams);
2983 if (jointBodies[0] == jointBodies[1])
2984 {
2985 DoJointErrorMessage(joint, "ERROR: joint cannot be created; the joint bodies are the same, body1==body2. Raw body is " + jointBodies[0] + ". raw parms: " + joint.RawParams);
2986 }
2987 else
2988 {
2989 switch (joint.Type)
2990 {
2991 case PhysicsJointType.Ball:
2992 {
2993 IntPtr odeJoint;
2994 //DoJointErrorMessage(joint, "ODE creating ball joint ");
2995 odeJoint = d.JointCreateBall(world, IntPtr.Zero);
2996 //DoJointErrorMessage(joint, "ODE attaching ball joint: " + odeJoint + " with b1:" + jointBodies[0] + " b2:" + jointBodies[1]);
2997 d.JointAttach(odeJoint, jointBodies[0], jointBodies[1]);
2998 //DoJointErrorMessage(joint, "ODE setting ball anchor: " + odeJoint + " to vec:" + joint.Position);
2999 d.JointSetBallAnchor(odeJoint,
3000 joint.Position.X,
3001 joint.Position.Y,
3002 joint.Position.Z);
3003 //DoJointErrorMessage(joint, "ODE joint setting OK");
3004 //DoJointErrorMessage(joint, "The ball joint's bodies are here: b0: ");
3005 //DoJointErrorMessage(joint, "" + (jointBodies[0] != IntPtr.Zero ? "" + d.BodyGetPosition(jointBodies[0]) : "fixed environment"));
3006 //DoJointErrorMessage(joint, "The ball joint's bodies are here: b1: ");
3007 //DoJointErrorMessage(joint, "" + (jointBodies[1] != IntPtr.Zero ? "" + d.BodyGetPosition(jointBodies[1]) : "fixed environment"));
3008
3009 if (joint is OdePhysicsJoint)
3010 {
3011 ((OdePhysicsJoint)joint).jointID = odeJoint;
3012 }
3013 else
3014 {
3015 DoJointErrorMessage(joint, "WARNING: non-ode joint in ODE!");
3016 }
3017 }
3018 break;
3019 case PhysicsJointType.Hinge:
3020 {
3021 IntPtr odeJoint;
3022 //DoJointErrorMessage(joint, "ODE creating hinge joint ");
3023 odeJoint = d.JointCreateHinge(world, IntPtr.Zero);
3024 //DoJointErrorMessage(joint, "ODE attaching hinge joint: " + odeJoint + " with b1:" + jointBodies[0] + " b2:" + jointBodies[1]);
3025 d.JointAttach(odeJoint, jointBodies[0], jointBodies[1]);
3026 //DoJointErrorMessage(joint, "ODE setting hinge anchor: " + odeJoint + " to vec:" + joint.Position);
3027 d.JointSetHingeAnchor(odeJoint,
3028 joint.Position.X,
3029 joint.Position.Y,
3030 joint.Position.Z);
3031 // We use the orientation of the x-axis of the joint's coordinate frame
3032 // as the axis for the hinge.
3033
3034 // Therefore, we must get the joint's coordinate frame based on the
3035 // joint.Rotation field, which originates from the orientation of the
3036 // joint's proxy object in the scene.
3037
3038 // The joint's coordinate frame is defined as the transformation matrix
3039 // that converts a vector from joint-local coordinates into world coordinates.
3040 // World coordinates are defined as the XYZ coordinate system of the sim,
3041 // as shown in the top status-bar of the viewer.
3042
3043 // Once we have the joint's coordinate frame, we extract its X axis (AtAxis)
3044 // and use that as the hinge axis.
3045
3046 //joint.Rotation.Normalize();
3047 Matrix4 proxyFrame = Matrix4.CreateFromQuaternion(joint.Rotation);
3048
3049 // Now extract the X axis of the joint's coordinate frame.
3050
3051 // Do not try to use proxyFrame.AtAxis or you will become mired in the
3052 // tar pit of transposed, inverted, and generally messed-up orientations.
3053 // (In other words, Matrix4.AtAxis() is borked.)
3054 // Vector3 jointAxis = proxyFrame.AtAxis; <--- this path leadeth to madness
3055
3056 // Instead, compute the X axis of the coordinate frame by transforming
3057 // the (1,0,0) vector. At least that works.
3058
3059 //m_log.Debug("PHY: making axis: complete matrix is " + proxyFrame);
3060 Vector3 jointAxis = Vector3.Transform(Vector3.UnitX, proxyFrame);
3061 //m_log.Debug("PHY: making axis: hinge joint axis is " + jointAxis);
3062 //DoJointErrorMessage(joint, "ODE setting hinge axis: " + odeJoint + " to vec:" + jointAxis);
3063 d.JointSetHingeAxis(odeJoint,
3064 jointAxis.X,
3065 jointAxis.Y,
3066 jointAxis.Z);
3067 //d.JointSetHingeParam(odeJoint, (int)dParam.CFM, 0.1f);
3068 if (joint is OdePhysicsJoint)
3069 {
3070 ((OdePhysicsJoint)joint).jointID = odeJoint;
3071 }
3072 else
3073 {
3074 DoJointErrorMessage(joint, "WARNING: non-ode joint in ODE!");
3075 }
3076 }
3077 break;
3078 }
3079 successfullyProcessedPendingJoints.Add(joint);
3080 }
3081 }
3082 else
3083 {
3084 DoJointErrorMessage(joint, "joint could not yet be created; still pending");
3085 }
3086 }
3087
3088 foreach (PhysicsJoint successfullyProcessedJoint in successfullyProcessedPendingJoints)
3089 {
3090 //DoJointErrorMessage(successfullyProcessedJoint, "finalizing succesfully procsssed joint " + successfullyProcessedJoint.ObjectNameInScene + " parms " + successfullyProcessedJoint.RawParams);
3091 //DoJointErrorMessage(successfullyProcessedJoint, "removing from pending");
3092 InternalRemovePendingJoint(successfullyProcessedJoint);
3093 //DoJointErrorMessage(successfullyProcessedJoint, "adding to active");
3094 InternalAddActiveJoint(successfullyProcessedJoint);
3095 //DoJointErrorMessage(successfullyProcessedJoint, "done");
3096 }
3097 }
3098 }
3099
3100 /// <summary>
3101 /// Simulate the joint proxies of a NINJA actor.
3102 /// </summary>
3103 /// <remarks>
3104 /// Called as part of the Simulate() loop if NINJA physics is active. Must only be called from there.
3105 /// </remarks>
3106 /// <param name="actor"></param>
3107 protected void SimulateActorPendingJoints(OdePrim actor)
3108 {
3109 // If an actor moved, move its joint proxy objects as well.
3110 // There seems to be an event PhysicsActor.OnPositionUpdate that could be used
3111 // for this purpose but it is never called! So we just do the joint
3112 // movement code here.
3113
3114 if (actor.SOPName != null &&
3115 joints_connecting_actor.ContainsKey(actor.SOPName) &&
3116 joints_connecting_actor[actor.SOPName] != null &&
3117 joints_connecting_actor[actor.SOPName].Count > 0)
3118 {
3119 foreach (PhysicsJoint affectedJoint in joints_connecting_actor[actor.SOPName])
3120 {
3121 if (affectedJoint.IsInPhysicsEngine)
3122 {
3123 DoJointMoved(affectedJoint);
3124 }
3125 else
3126 {
3127 DoJointErrorMessage(affectedJoint, "a body connected to a joint was moved, but the joint doesn't exist yet! this will lead to joint error. joint was: " + affectedJoint.ObjectNameInScene + " parms:" + affectedJoint.RawParams);
3128 }
3129 }
3130 }
3131 }
3132
3114 public override void GetResults() 3133 public override void GetResults()
3115 { 3134 {
3116 } 3135 }
@@ -3456,24 +3475,21 @@ namespace OpenSim.Region.Physics.OdePlugin
3456 float hfmin = 2000; 3475 float hfmin = 2000;
3457 float hfmax = -2000; 3476 float hfmax = -2000;
3458 3477
3459 for (int x = 0; x < heightmapWidthSamples; x++) 3478 for (int x = 0; x < heightmapWidthSamples; x++)
3479 {
3480 for (int y = 0; y < heightmapHeightSamples; y++)
3460 { 3481 {
3461 for (int y = 0; y < heightmapHeightSamples; y++) 3482 int xx = Util.Clip(x - 1, 0, regionsize - 1);
3462 { 3483 int yy = Util.Clip(y - 1, 0, regionsize - 1);
3463 int xx = Util.Clip(x - 1, 0, regionsize - 1); 3484
3464 int yy = Util.Clip(y - 1, 0, regionsize - 1); 3485
3465 3486 float val= heightMap[yy * (int)Constants.RegionSize + xx];
3466 3487 _heightmap[x * ((int)Constants.RegionSize + 2) + y] = val;
3467 float val= heightMap[yy * (int)Constants.RegionSize + xx]; 3488
3468 _heightmap[x * ((int)Constants.RegionSize + 2) + y] = val; 3489 hfmin = (val < hfmin) ? val : hfmin;
3469 3490 hfmax = (val > hfmax) ? val : hfmax;
3470 hfmin = (val < hfmin) ? val : hfmin;
3471 hfmax = (val > hfmax) ? val : hfmax;
3472 }
3473 } 3491 }
3474 3492 }
3475
3476
3477 3493
3478 lock (OdeLock) 3494 lock (OdeLock)
3479 { 3495 {
@@ -3528,7 +3544,6 @@ namespace OpenSim.Region.Physics.OdePlugin
3528 } 3544 }
3529 RegionTerrain.Add(pOffset, GroundGeom, GroundGeom); 3545 RegionTerrain.Add(pOffset, GroundGeom, GroundGeom);
3530 TerrainHeightFieldHeights.Add(GroundGeom,_heightmap); 3546 TerrainHeightFieldHeights.Add(GroundGeom,_heightmap);
3531
3532 } 3547 }
3533 } 3548 }
3534 3549
@@ -3691,6 +3706,7 @@ namespace OpenSim.Region.Physics.OdePlugin
3691 //d.CloseODE(); 3706 //d.CloseODE();
3692 } 3707 }
3693 } 3708 }
3709
3694 public override Dictionary<uint, float> GetTopColliders() 3710 public override Dictionary<uint, float> GetTopColliders()
3695 { 3711 {
3696 Dictionary<uint, float> returncolliders = new Dictionary<uint, float>(); 3712 Dictionary<uint, float> returncolliders = new Dictionary<uint, float>();
@@ -3727,6 +3743,34 @@ namespace OpenSim.Region.Physics.OdePlugin
3727 } 3743 }
3728 } 3744 }
3729 3745
3746 public override void RaycastWorld(Vector3 position, Vector3 direction, float length, int Count, RayCallback retMethod)
3747 {
3748 if (retMethod != null)
3749 {
3750 m_rayCastManager.QueueRequest(position, direction, length, Count, retMethod);
3751 }
3752 }
3753
3754 public override List<ContactResult> RaycastWorld(Vector3 position, Vector3 direction, float length, int Count)
3755 {
3756 ContactResult[] ourResults = null;
3757 RayCallback retMethod = delegate(List<ContactResult> results)
3758 {
3759 ourResults = new ContactResult[results.Count];
3760 results.CopyTo(ourResults, 0);
3761 };
3762 int waitTime = 0;
3763 m_rayCastManager.QueueRequest(position, direction, length, Count, retMethod);
3764 while (ourResults == null && waitTime < 1000)
3765 {
3766 Thread.Sleep(1);
3767 waitTime++;
3768 }
3769 if (ourResults == null)
3770 return new List<ContactResult> ();
3771 return new List<ContactResult>(ourResults);
3772 }
3773
3730#if USE_DRAWSTUFF 3774#if USE_DRAWSTUFF
3731 // Keyboard callback 3775 // Keyboard callback
3732 public void command(int cmd) 3776 public void command(int cmd)
diff --git a/OpenSim/Region/Physics/OdePlugin/Tests/ODETestClass.cs b/OpenSim/Region/Physics/OdePlugin/Tests/ODETestClass.cs
index 5dcd6f5..2ea810f 100644
--- a/OpenSim/Region/Physics/OdePlugin/Tests/ODETestClass.cs
+++ b/OpenSim/Region/Physics/OdePlugin/Tests/ODETestClass.cs
@@ -31,17 +31,18 @@ using NUnit.Framework;
31using OpenMetaverse; 31using OpenMetaverse;
32using OpenSim.Framework; 32using OpenSim.Framework;
33using OpenSim.Region.Physics.Manager; 33using OpenSim.Region.Physics.Manager;
34using OpenSim.Region.Physics.OdePlugin;
34using log4net; 35using log4net;
35using System.Reflection; 36using System.Reflection;
36 37
37namespace OpenSim.Region.Physics.OdePlugin 38namespace OpenSim.Region.Physics.OdePlugin.Tests
38{ 39{
39 [TestFixture] 40 [TestFixture]
40 public class ODETestClass 41 public class ODETestClass
41 { 42 {
42 private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); 43 private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
43 44
44 private OdePlugin cbt; 45 private OpenSim.Region.Physics.OdePlugin.OdePlugin cbt;
45 private PhysicsScene ps; 46 private PhysicsScene ps;
46 private IMeshingPlugin imp; 47 private IMeshingPlugin imp;
47 48