diff options
Diffstat (limited to 'OpenSim/Region/Physics')
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 | */ | ||
27 | using System; | ||
28 | using System.Collections.Generic; | ||
29 | using System.Reflection; | ||
30 | using log4net; | ||
31 | using OpenMetaverse; | ||
32 | using OpenSim.Framework; | ||
33 | using OpenSim.Region.Physics.Manager; | ||
34 | |||
35 | namespace OpenSim.Region.Physics.BulletSPlugin | ||
36 | { | ||
37 | public 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 | |||
44 | using System; | ||
45 | using System.Collections.Generic; | ||
46 | using System.Reflection; | ||
47 | using System.Runtime.InteropServices; | ||
48 | using log4net; | ||
49 | using OpenMetaverse; | ||
50 | using OpenSim.Framework; | ||
51 | using OpenSim.Region.Physics.Manager; | ||
52 | |||
53 | namespace 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 | */ | ||
27 | using System; | ||
28 | using System.Collections.Generic; | ||
29 | using OpenSim.Framework; | ||
30 | using OpenSim.Region.Physics.Manager; | ||
31 | using OpenMetaverse; | ||
32 | |||
33 | namespace OpenSim.Region.Physics.BulletSPlugin | ||
34 | { | ||
35 | public 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 | */ | ||
27 | using System; | ||
28 | using System.Reflection; | ||
29 | using System.Collections.Generic; | ||
30 | using System.Xml; | ||
31 | using log4net; | ||
32 | using OMV = OpenMetaverse; | ||
33 | using OpenSim.Framework; | ||
34 | using OpenSim.Region.Physics.Manager; | ||
35 | using OpenSim.Region.Physics.ConvexDecompositionDotNet; | ||
36 | |||
37 | namespace OpenSim.Region.Physics.BulletSPlugin | ||
38 | { | ||
39 | [Serializable] | ||
40 | public 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 | */ | ||
27 | using System; | ||
28 | using System.Collections.Generic; | ||
29 | using System.Runtime.InteropServices; | ||
30 | using System.Text; | ||
31 | using System.Threading; | ||
32 | using Nini.Config; | ||
33 | using log4net; | ||
34 | using OpenSim.Framework; | ||
35 | using OpenSim.Region.Physics.Manager; | ||
36 | using OpenMetaverse; | ||
37 | using 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 | // | ||
56 | namespace OpenSim.Region.Physics.BulletSPlugin | ||
57 | { | ||
58 | public 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 | */ | ||
27 | using System; | ||
28 | using System.Runtime.InteropServices; | ||
29 | using System.Security; | ||
30 | using System.Text; | ||
31 | using OpenMetaverse; | ||
32 | |||
33 | namespace OpenSim.Region.Physics.BulletSPlugin { | ||
34 | |||
35 | [StructLayout(LayoutKind.Sequential)] | ||
36 | public struct ConvexHull | ||
37 | { | ||
38 | Vector3 Offset; | ||
39 | int VertexCount; | ||
40 | Vector3[] Vertices; | ||
41 | } | ||
42 | [StructLayout(LayoutKind.Sequential)] | ||
43 | public 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)] | ||
75 | public struct SweepHit | ||
76 | { | ||
77 | public uint ID; | ||
78 | public float Fraction; | ||
79 | public Vector3 Normal; | ||
80 | public Vector3 Point; | ||
81 | } | ||
82 | [StructLayout(LayoutKind.Sequential)] | ||
83 | public struct RaycastHit | ||
84 | { | ||
85 | public uint ID; | ||
86 | public float Fraction; | ||
87 | public Vector3 Normal; | ||
88 | } | ||
89 | [StructLayout(LayoutKind.Sequential)] | ||
90 | public struct CollisionDesc | ||
91 | { | ||
92 | public uint aID; | ||
93 | public uint bID; | ||
94 | public Vector3 point; | ||
95 | public Vector3 normal; | ||
96 | } | ||
97 | [StructLayout(LayoutKind.Sequential)] | ||
98 | public 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)] | ||
110 | public 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 | |||
139 | static class BulletSimAPI { | ||
140 | |||
141 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
142 | [return: MarshalAs(UnmanagedType.LPStr)] | ||
143 | public static extern string GetVersion(); | ||
144 | |||
145 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
146 | public 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] | ||
151 | public static extern bool UpdateParameter(uint worldID, uint localID, | ||
152 | [MarshalAs(UnmanagedType.LPStr)]string paramCode, float value); | ||
153 | |||
154 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
155 | public static extern void SetHeightmap(uint worldID, [MarshalAs(UnmanagedType.LPArray)] float[] heightMap); | ||
156 | |||
157 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
158 | public static extern void Shutdown(uint worldID); | ||
159 | |||
160 | |||
161 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
162 | public 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] | ||
169 | public 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] | ||
174 | public 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] | ||
180 | public static extern bool DestroyHull(uint worldID, System.UInt64 meshKey); | ||
181 | |||
182 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
183 | public static extern bool DestroyMesh(uint worldID, System.UInt64 meshKey); | ||
184 | |||
185 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
186 | public static extern bool CreateObject(uint worldID, ShapeData shapeData); | ||
187 | |||
188 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
189 | public static extern void CreateLinkset(uint worldID, int objectCount, ShapeData[] shapeDatas); | ||
190 | |||
191 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
192 | public 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] | ||
198 | public static extern bool RemoveConstraintByID(uint worldID, uint id1); | ||
199 | |||
200 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
201 | public static extern bool RemoveConstraint(uint worldID, uint id1, uint id2); | ||
202 | |||
203 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
204 | public static extern Vector3 GetObjectPosition(uint WorldID, uint id); | ||
205 | |||
206 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
207 | public static extern bool SetObjectTranslation(uint worldID, uint id, Vector3 position, Quaternion rotation); | ||
208 | |||
209 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
210 | public static extern bool SetObjectVelocity(uint worldID, uint id, Vector3 velocity); | ||
211 | |||
212 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
213 | public static extern bool SetObjectAngularVelocity(uint worldID, uint id, Vector3 angularVelocity); | ||
214 | |||
215 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
216 | public static extern bool SetObjectForce(uint worldID, uint id, Vector3 force); | ||
217 | |||
218 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
219 | public static extern bool SetObjectScaleMass(uint worldID, uint id, Vector3 scale, float mass, bool isDynamic); | ||
220 | |||
221 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
222 | public static extern bool SetObjectCollidable(uint worldID, uint id, bool phantom); | ||
223 | |||
224 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
225 | public static extern bool SetObjectDynamic(uint worldID, uint id, bool isDynamic, float mass); | ||
226 | |||
227 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
228 | public static extern bool SetObjectGhost(uint worldID, uint id, bool ghostly); | ||
229 | |||
230 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
231 | public static extern bool SetObjectProperties(uint worldID, uint id, bool isStatic, bool isSolid, bool genCollisions, float mass); | ||
232 | |||
233 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
234 | public static extern bool SetObjectBuoyancy(uint worldID, uint id, float buoyancy); | ||
235 | |||
236 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
237 | public static extern bool HasObject(uint worldID, uint id); | ||
238 | |||
239 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
240 | public static extern bool DestroyObject(uint worldID, uint id); | ||
241 | |||
242 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
243 | public static extern SweepHit ConvexSweepTest(uint worldID, uint id, Vector3 to, float extraMargin); | ||
244 | |||
245 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
246 | public static extern RaycastHit RayTest(uint worldID, uint id, Vector3 from, Vector3 to); | ||
247 | |||
248 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
249 | public static extern Vector3 RecoverFromPenetration(uint worldID, uint id); | ||
250 | |||
251 | // Log a debug message | ||
252 | [UnmanagedFunctionPointer(CallingConvention.Cdecl)] | ||
253 | public delegate void DebugLogCallback([MarshalAs(UnmanagedType.LPStr)]string msg); | ||
254 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
255 | public 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 | |||
28 | using System; | ||
29 | using System.Collections.Generic; | ||
30 | |||
31 | namespace 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 | |||
28 | using System; | ||
29 | using System.Collections.Generic; | ||
30 | using System.Text; | ||
31 | |||
32 | namespace 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 | |||
28 | using System; | ||
29 | using System.Collections.Generic; | ||
30 | using System.Diagnostics; | ||
31 | |||
32 | namespace 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 | |||
28 | using System; | ||
29 | using System.Collections.Generic; | ||
30 | using System.Diagnostics; | ||
31 | |||
32 | namespace 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 | |||
28 | using System; | ||
29 | using System.Collections.Generic; | ||
30 | |||
31 | namespace 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 | |||
28 | using System; | ||
29 | using System.Collections.Generic; | ||
30 | |||
31 | namespace 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 | |||
28 | using System; | ||
29 | using System.Collections.Generic; | ||
30 | using System.Diagnostics; | ||
31 | |||
32 | namespace 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 | |||
28 | using System; | ||
29 | using System.Collections.Generic; | ||
30 | using System.Diagnostics; | ||
31 | |||
32 | namespace 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 @@ | |||
1 | ConvexDecompositionDotNet | ||
2 | ------------------------- | ||
3 | |||
4 | The MIT License | ||
5 | |||
6 | Copyright (c) 2010 Intel Corporation. | ||
7 | All rights reserved. | ||
8 | |||
9 | Based on the convexdecomposition library from | ||
10 | <http://codesuppository.googlecode.com> by John W. Ratcliff and Stan Melax. | ||
11 | |||
12 | Permission is hereby granted, free of charge, to any person obtaining a copy | ||
13 | of this software and associated documentation files (the "Software"), to deal | ||
14 | in the Software without restriction, including without limitation the rights | ||
15 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | ||
16 | copies of the Software, and to permit persons to whom the Software is | ||
17 | furnished to do so, subject to the following conditions: | ||
18 | |||
19 | The above copyright notice and this permission notice shall be included in | ||
20 | all copies or substantial portions of the Software. | ||
21 | |||
22 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||
23 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||
24 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | ||
25 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | ||
26 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | ||
27 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN | ||
28 | THE 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 | |||
28 | using System; | ||
29 | |||
30 | namespace 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 | |||
28 | using System; | ||
29 | using System.Collections.Generic; | ||
30 | using System.Diagnostics; | ||
31 | |||
32 | namespace 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 @@ | |||
1 | using System.Reflection; | ||
2 | using System.Runtime.CompilerServices; | ||
3 | using 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 | |||
28 | using System; | ||
29 | |||
30 | namespace 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 @@ | |||
1 | ConvexDecompositionDotNet | ||
2 | ========================= | ||
3 | |||
4 | A C# port of the ConvexDecomposition library by John W. Ratcliff and Stan Melax. | ||
5 | The original C++ version is available at <http://codesuppository.googlecode.com/>. | ||
6 | See the blog post at <http://codesuppository.blogspot.com/2006/08/approximate-convexdecomposition.html> | ||
7 | for 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 | |||
28 | using System; | ||
29 | using System.Collections.Generic; | ||
30 | |||
31 | namespace 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 | |||
28 | using System; | ||
29 | using System.Collections.Generic; | ||
30 | |||
31 | namespace 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 | |||
28 | using System; | ||
29 | |||
30 | namespace 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 | |||
28 | using System; | ||
29 | |||
30 | namespace 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 | |||
28 | using System; | ||
29 | using System.Collections.Generic; | ||
30 | using System.Diagnostics; | ||
31 | |||
32 | namespace 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 | |||
28 | using System; | ||
29 | |||
30 | namespace 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 | |||
28 | using System; | ||
29 | using System.Collections.Generic; | ||
30 | using System.Linq; | ||
31 | using System.Text; | ||
32 | |||
33 | namespace 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 | |||
28 | using System; | ||
29 | |||
30 | namespace 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 | |||
28 | using System; | ||
29 | |||
30 | namespace 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 | |||
28 | using System; | ||
29 | using System.Collections.Generic; | ||
30 | using OpenSim.Framework; | ||
31 | using OpenMetaverse; | ||
32 | |||
33 | namespace 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 | { |
862 | Console.WriteLine("ProcessTaints for " + Name); | 889 | #if SPAM |
890 | Console.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) | 1362 | Console.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 |
1426 | Console.WriteLine("changeadd 1"); | 1495 | Console.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 | ||
1949 | Console.WriteLine("changesize 1"); | ||
1950 | #endif | ||
1951 | CreateGeom(m_targetSpace, mesh); | ||
1952 | } | ||
1953 | else | ||
1954 | { | ||
1955 | _mesh = null; | ||
1956 | |||
1957 | #if SPAM | ||
1958 | Console.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); |
2062 | Console.WriteLine("changeshape needed meshing"); | ||
2063 | #endif | ||
2064 | CreateGeom(m_targetSpace, mesh); | ||
2065 | } | ||
2066 | else | ||
2067 | { | ||
2068 | _mesh = null; | ||
2069 | |||
2070 | #if SPAM | ||
2071 | Console.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 | ||
31 | using System; | 31 | using System; |
32 | using System.Collections.Generic; | 32 | using 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 |
2571 | Console.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; | |||
31 | using OpenMetaverse; | 31 | using OpenMetaverse; |
32 | using OpenSim.Framework; | 32 | using OpenSim.Framework; |
33 | using OpenSim.Region.Physics.Manager; | 33 | using OpenSim.Region.Physics.Manager; |
34 | using OpenSim.Region.Physics.OdePlugin; | ||
34 | using log4net; | 35 | using log4net; |
35 | using System.Reflection; | 36 | using System.Reflection; |
36 | 37 | ||
37 | namespace OpenSim.Region.Physics.OdePlugin | 38 | namespace 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 | ||