aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/OpenSim/Region/Physics/OdePlugin/ODEPrim.cs
diff options
context:
space:
mode:
Diffstat (limited to 'OpenSim/Region/Physics/OdePlugin/ODEPrim.cs')
-rw-r--r--OpenSim/Region/Physics/OdePlugin/ODEPrim.cs686
1 files changed, 686 insertions, 0 deletions
diff --git a/OpenSim/Region/Physics/OdePlugin/ODEPrim.cs b/OpenSim/Region/Physics/OdePlugin/ODEPrim.cs
new file mode 100644
index 0000000..f423e82
--- /dev/null
+++ b/OpenSim/Region/Physics/OdePlugin/ODEPrim.cs
@@ -0,0 +1,686 @@
1using System;
2using System.Collections.Generic;
3using Axiom.Math;
4using Ode.NET;
5using OpenSim.Framework;
6using OpenSim.Region.Physics.Manager;
7
8namespace OpenSim.Region.Physics.OdePlugin
9{
10
11 public class OdePrim : PhysicsActor
12 {
13 public PhysicsVector _position;
14 private PhysicsVector _velocity;
15 private PhysicsVector m_lastVelocity = new PhysicsVector(0.0f, 0.0f, 0.0f);
16 private PhysicsVector m_lastposition = new PhysicsVector(0.0f, 0.0f, 0.0f);
17 private PhysicsVector m_rotationalVelocity;
18 private PhysicsVector _size;
19 private PhysicsVector _acceleration;
20 private Quaternion _orientation;
21 private PhysicsVector m_taintposition;
22 private PhysicsVector m_taintsize;
23 private Quaternion m_taintrot;
24 private bool m_taintshape = false;
25 private bool m_taintPhysics = false;
26 public bool m_taintremove = false;
27
28 private IMesh _mesh;
29 private PrimitiveBaseShape _pbs;
30 private OdeScene _parent_scene;
31 public IntPtr m_targetSpace = (IntPtr)0;
32 public IntPtr prim_geom;
33 public IntPtr _triMeshData;
34 private bool iscolliding = false;
35 private bool m_isphysical = false;
36 private bool m_throttleUpdates = false;
37 private int throttleCounter = 0;
38 public bool outofBounds = false;
39
40 public bool _zeroFlag = false;
41 private bool m_lastUpdateSent = false;
42
43 public IntPtr Body = (IntPtr)0;
44 private String m_primName;
45 private PhysicsVector _target_velocity;
46 public d.Mass pMass;
47 private const float MassMultiplier = 150f; // Ref: Water: 1000kg.. this iset to 500
48 private int debugcounter = 0;
49
50
51 public OdePrim(String primName, OdeScene parent_scene, IntPtr targetSpace, PhysicsVector pos, PhysicsVector size,
52 Quaternion rotation, IMesh mesh, PrimitiveBaseShape pbs, bool pisPhysical)
53 {
54
55
56 _velocity = new PhysicsVector();
57 _position = pos;
58 m_taintposition = pos;
59 if (_position.X > 257)
60 {
61 _position.X = 257;
62 }
63 if (_position.X < 0)
64 {
65 _position.X = 0;
66 }
67 if (_position.Y > 257)
68 {
69 _position.Y = 257;
70 }
71 if (_position.Y < 0)
72 {
73 _position.Y = 0;
74 }
75
76 _size = size;
77 m_taintsize = _size;
78 _acceleration = new PhysicsVector();
79 m_rotationalVelocity = PhysicsVector.Zero;
80 _orientation = rotation;
81 m_taintrot = _orientation;
82 _mesh = mesh;
83 _pbs = pbs;
84
85 _parent_scene = parent_scene;
86 m_targetSpace = targetSpace;
87
88 if (pos.Z < 0)
89 m_isphysical = false;
90 else
91 {
92 m_isphysical = pisPhysical;
93 // If we're physical, we need to be in the master space for now.
94 // linksets *should* be in a space together.. but are not currently
95 if (m_isphysical)
96 m_targetSpace = _parent_scene.space;
97
98 }
99 m_primName = primName;
100
101
102
103 lock (OdeScene.OdeLock)
104 {
105 if (mesh != null)
106 {
107 setMesh(parent_scene, mesh);
108 }
109 else
110 {
111 prim_geom = d.CreateBox(m_targetSpace, _size.X, _size.Y, _size.Z);
112 }
113
114 d.GeomSetPosition(prim_geom, _position.X, _position.Y, _position.Z);
115 d.Quaternion myrot = new d.Quaternion();
116 myrot.W = rotation.w;
117 myrot.X = rotation.x;
118 myrot.Y = rotation.y;
119 myrot.Z = rotation.z;
120 d.GeomSetQuaternion(prim_geom, ref myrot);
121
122
123 if (m_isphysical && Body == (IntPtr)0)
124 {
125 enableBody();
126 }
127 parent_scene.geom_name_map[prim_geom] = primName;
128 parent_scene.actor_name_map[prim_geom] = (PhysicsActor)this;
129 // don't do .add() here; old geoms get recycled with the same hash
130 }
131 }
132 public override int PhysicsActorType
133 {
134 get { return (int)ActorTypes.Prim; }
135 set { return; }
136 }
137 public override bool SetAlwaysRun
138 {
139 get { return false; }
140 set { return; }
141 }
142 public void enableBody()
143 {
144 // Sets the geom to a body
145 Body = d.BodyCreate(_parent_scene.world);
146
147 setMass();
148 d.BodySetPosition(Body, _position.X, _position.Y, _position.Z);
149 d.Quaternion myrot = new d.Quaternion();
150 myrot.W = _orientation.w;
151 myrot.X = _orientation.x;
152 myrot.Y = _orientation.y;
153 myrot.Z = _orientation.z;
154 d.BodySetQuaternion(Body, ref myrot);
155 d.GeomSetBody(prim_geom, Body);
156 d.BodySetAutoDisableFlag(Body, true);
157 d.BodySetAutoDisableSteps(Body, 20);
158
159 _parent_scene.addActivePrim(this);
160 }
161 public void setMass()
162 {
163 //Sets Mass based on member MassMultiplier.
164 if (Body != (IntPtr)0)
165 {
166 d.MassSetBox(out pMass, (_size.X * _size.Y * _size.Z * MassMultiplier), _size.X, _size.Y, _size.Z);
167 d.BodySetMass(Body, ref pMass);
168 }
169 }
170 public void disableBody()
171 {
172 //this kills the body so things like 'mesh' can re-create it.
173 if (Body != (IntPtr)0)
174 {
175 _parent_scene.remActivePrim(this);
176 d.BodyDestroy(Body);
177 Body = (IntPtr)0;
178 }
179 }
180 public void setMesh(OdeScene parent_scene, IMesh mesh)
181 {
182 //Kill Body so that mesh can re-make the geom
183 if (IsPhysical && Body != (IntPtr)0)
184 {
185 disableBody();
186 }
187 float[] vertexList = mesh.getVertexListAsFloatLocked(); // Note, that vertextList is pinned in memory
188 int[] indexList = mesh.getIndexListAsIntLocked(); // Also pinned, needs release after usage
189 int VertexCount = vertexList.GetLength(0) / 3;
190 int IndexCount = indexList.GetLength(0);
191
192 _triMeshData = d.GeomTriMeshDataCreate();
193
194 d.GeomTriMeshDataBuildSimple(_triMeshData, vertexList, 3 * sizeof(float), VertexCount, indexList, IndexCount,
195 3 * sizeof(int));
196 d.GeomTriMeshDataPreprocess(_triMeshData);
197
198 prim_geom = d.CreateTriMesh(m_targetSpace, _triMeshData, parent_scene.triCallback, null, null);
199
200 if (IsPhysical && Body == (IntPtr)0)
201 {
202 // Recreate the body
203 enableBody();
204 }
205 }
206 public void ProcessTaints(float timestep)
207 {
208 if (m_taintposition != _position)
209 Move(timestep);
210
211 if (m_taintrot != _orientation)
212 rotate(timestep);
213 //
214
215 if (m_taintPhysics != m_isphysical)
216 changePhysicsStatus(timestep);
217 //
218
219 if (m_taintsize != _size)
220 changesize(timestep);
221 //
222
223 if (m_taintshape)
224 changeshape(timestep);
225 //
226
227 }
228 public void Move(float timestep)
229 {
230 if (m_isphysical)
231 {
232 // This is a fallback.. May no longer be necessary.
233 if (Body == (IntPtr)0)
234 enableBody();
235 //Prim auto disable after 20 frames,
236 ///if you move it, re-enable the prim manually.
237 d.BodyEnable(Body);
238 d.BodySetPosition(Body, _position.X, _position.Y, _position.Z);
239 }
240 else
241 {
242 string primScenAvatarIn = _parent_scene.whichspaceamIin(_position);
243 int[] arrayitem = _parent_scene.calculateSpaceArrayItemFromPos(_position);
244 if (primScenAvatarIn == "0")
245 {
246 OpenSim.Framework.Console.MainLog.Instance.Verbose("Physics", "Prim " + m_primName + " in space with no prim: " + primScenAvatarIn + ". Expected to be at: " + m_targetSpace.ToString() + " . Arr:': " + arrayitem[0].ToString() + "," + arrayitem[1].ToString());
247 }
248 else
249 {
250 OpenSim.Framework.Console.MainLog.Instance.Verbose("Physics", "Prim " + m_primName + " in Prim space with prim: " + primScenAvatarIn + ". Expected to be at: " + m_targetSpace.ToString() + ". Arr:" + arrayitem[0].ToString() + "," + arrayitem[1].ToString());
251 }
252 m_targetSpace = _parent_scene.recalculateSpaceForGeom(prim_geom, _position, m_targetSpace);
253 d.GeomSetPosition(prim_geom, _position.X, _position.Y, _position.Z);
254 d.SpaceAdd(m_targetSpace, prim_geom);
255 }
256
257 m_taintposition = _position;
258 }
259 public void rotate(float timestep)
260 {
261
262 d.Quaternion myrot = new d.Quaternion();
263 myrot.W = _orientation.w;
264 myrot.X = _orientation.x;
265 myrot.Y = _orientation.y;
266 myrot.Z = _orientation.z;
267 d.GeomSetQuaternion(prim_geom, ref myrot);
268 if (m_isphysical && Body != (IntPtr)0)
269 {
270 d.BodySetQuaternion(Body, ref myrot);
271 }
272
273 m_taintrot = _orientation;
274 }
275 public void changePhysicsStatus(float timestap)
276 {
277 if (m_isphysical == true)
278 {
279 if (Body == (IntPtr)0)
280 {
281 enableBody();
282 }
283
284 }
285 else
286 {
287 if (Body != (IntPtr)0)
288 {
289 disableBody();
290 }
291 }
292
293
294 m_taintPhysics = m_isphysical;
295 }
296 public void changesize(float timestamp)
297 {
298 string oldname = _parent_scene.geom_name_map[prim_geom];
299
300 // Cleanup of old prim geometry
301 if (_mesh != null)
302 {
303 // Cleanup meshing here
304 }
305 //kill body to rebuild
306 if (IsPhysical && Body != (IntPtr)0)
307 {
308 disableBody();
309 }
310 if (d.SpaceQuery(m_targetSpace, prim_geom))
311 {
312 d.SpaceRemove(m_targetSpace, prim_geom);
313 }
314 d.GeomDestroy(prim_geom);
315
316 // we don't need to do space calculation because the client sends a position update also.
317
318 // Construction of new prim
319 if (this._parent_scene.needsMeshing(_pbs))
320 {
321
322
323 // Don't need to re-enable body.. it's done in SetMesh
324 IMesh mesh = _parent_scene.mesher.CreateMesh(oldname, _pbs, _size);
325 // createmesh returns null when it's a shape that isn't a cube.
326 if (mesh != null)
327 {
328 setMesh(_parent_scene, mesh);
329 }
330 else
331 {
332 prim_geom = d.CreateBox(m_targetSpace, _size.X, _size.Y, _size.Z);
333 d.GeomSetPosition(prim_geom, _position.X, _position.Y, _position.Z);
334 d.Quaternion myrot = new d.Quaternion();
335 myrot.W = _orientation.w;
336 myrot.X = _orientation.x;
337 myrot.Y = _orientation.y;
338 myrot.Z = _orientation.z;
339 d.GeomSetQuaternion(prim_geom, ref myrot);
340
341
342 }
343 }
344 else
345 {
346 prim_geom = d.CreateBox(m_targetSpace, _size.X, _size.Y, _size.Z);
347 d.GeomSetPosition(prim_geom, _position.X, _position.Y, _position.Z);
348 d.Quaternion myrot = new d.Quaternion();
349 myrot.W = _orientation.w;
350 myrot.X = _orientation.x;
351 myrot.Y = _orientation.y;
352 myrot.Z = _orientation.z;
353 d.GeomSetQuaternion(prim_geom, ref myrot);
354
355
356 //d.GeomBoxSetLengths(prim_geom, _size.X, _size.Y, _size.Z);
357 if (IsPhysical && Body == (IntPtr)0)
358 {
359 // Re creates body on size.
360 // EnableBody also does setMass()
361 enableBody();
362 d.BodyEnable(Body);
363 }
364
365 }
366
367
368 _parent_scene.geom_name_map[prim_geom] = oldname;
369
370
371 m_taintsize = _size;
372 }
373 public void changeshape(float timestamp)
374 {
375 string oldname = _parent_scene.geom_name_map[prim_geom];
376
377 // Cleanup of old prim geometry and Bodies
378 if (IsPhysical && Body != (IntPtr)0)
379 {
380 disableBody();
381 }
382 d.GeomDestroy(prim_geom);
383 if (_mesh != null)
384 {
385
386 d.GeomBoxSetLengths(prim_geom, _size.X, _size.Y, _size.Z);
387
388 }
389
390 // Construction of new prim
391 if (this._parent_scene.needsMeshing(_pbs))
392 {
393 IMesh mesh = _parent_scene.mesher.CreateMesh(oldname, _pbs, _size);
394 if (mesh != null)
395 {
396 setMesh(_parent_scene, mesh);
397 }
398 else
399 {
400 prim_geom = d.CreateBox(m_targetSpace, _size.X, _size.Y, _size.Z);
401 }
402 }
403 else
404 {
405 prim_geom = d.CreateBox(m_targetSpace, _size.X, _size.Y, _size.Z);
406 }
407 if (IsPhysical && Body == (IntPtr)0)
408 {
409 //re-create new body
410 enableBody();
411 }
412 else
413 {
414 d.GeomSetPosition(prim_geom, _position.X, _position.Y, _position.Z);
415 d.Quaternion myrot = new d.Quaternion();
416 myrot.W = _orientation.w;
417 myrot.X = _orientation.x;
418 myrot.Y = _orientation.y;
419 myrot.Z = _orientation.z;
420 d.GeomSetQuaternion(prim_geom, ref myrot);
421 }
422 _parent_scene.geom_name_map[prim_geom] = oldname;
423
424
425
426
427 m_taintshape = false;
428 }
429 public override bool IsPhysical
430 {
431 get { return m_isphysical; }
432 set { m_isphysical = value; }
433 }
434 public void setPrimForRemoval()
435 {
436 m_taintremove = true;
437 }
438
439 public override bool Flying
440 {
441 get
442 {
443 return false; //no flying prims for you
444 }
445 set { }
446 }
447
448 public override bool IsColliding
449 {
450 get { return iscolliding; }
451 set { iscolliding = value; }
452 }
453 public override bool CollidingGround
454 {
455 get { return false; }
456 set { return; }
457 }
458 public override bool CollidingObj
459 {
460 get { return false; }
461 set { return; }
462 }
463 public override bool ThrottleUpdates
464 {
465 get { return m_throttleUpdates; }
466 set { m_throttleUpdates = value; }
467 }
468
469 public override PhysicsVector Position
470 {
471 get { return _position; }
472
473
474 set
475 {
476 _position = value;
477
478 }
479 }
480
481 public override PhysicsVector Size
482 {
483 get { return _size; }
484 set
485 {
486 _size = value;
487
488 }
489 }
490
491 public override PrimitiveBaseShape Shape
492 {
493 set
494 {
495 _pbs = value;
496
497 }
498 }
499
500 public override PhysicsVector Velocity
501 {
502 get
503 {
504 // Averate previous velocity with the new one so
505 // client object interpolation works a 'little' better
506 PhysicsVector returnVelocity = new PhysicsVector();
507 returnVelocity.X = (m_lastVelocity.X + _velocity.X) / 2;
508 returnVelocity.Y = (m_lastVelocity.Y + _velocity.Y) / 2;
509 returnVelocity.Z = (m_lastVelocity.Z + _velocity.Z) / 2;
510 return returnVelocity;
511 }
512 set { _velocity = value; }
513 }
514
515 public override bool Kinematic
516 {
517 get { return false; }
518 set { }
519 }
520
521 public override Quaternion Orientation
522 {
523 get { return _orientation; }
524 set
525 {
526 _orientation = value;
527
528 }
529 }
530
531 public override PhysicsVector Acceleration
532 {
533 get { return _acceleration; }
534 }
535
536
537 public void SetAcceleration(PhysicsVector accel)
538 {
539 _acceleration = accel;
540 }
541
542 public override void AddForce(PhysicsVector force)
543 {
544 }
545
546 public override PhysicsVector RotationalVelocity
547 {
548 get { return m_rotationalVelocity; }
549 set { m_rotationalVelocity = value; }
550 }
551
552 public void UpdatePositionAndVelocity()
553 {
554 // no lock; called from Simulate() -- if you call this from elsewhere, gotta lock or do Monitor.Enter/Exit!
555
556 if (Body != (IntPtr)0)
557 {
558 d.Vector3 vec = d.BodyGetPosition(Body);
559 d.Quaternion ori = d.BodyGetQuaternion(Body);
560 d.Vector3 vel = d.BodyGetLinearVel(Body);
561 d.Vector3 rotvel = d.BodyGetAngularVel(Body);
562
563 PhysicsVector l_position = new PhysicsVector();
564 // kluge to keep things in bounds. ODE lets dead avatars drift away (they should be removed!)
565 if (vec.X < 0.0f) vec.X = 0.0f;
566 if (vec.Y < 0.0f) vec.Y = 0.0f;
567 if (vec.X > 255.95f) vec.X = 255.95f;
568 if (vec.Y > 255.95f) vec.Y = 255.95f;
569 m_lastposition = _position;
570
571 l_position.X = vec.X;
572 l_position.Y = vec.Y;
573 l_position.Z = vec.Z;
574 if (l_position.Z < 0)
575 {
576 // This is so prim that get lost underground don't fall forever and suck up
577 //
578 // Sim resources and memory.
579 // Disables the prim's movement physics....
580 // It's a hack and will generate a console message if it fails.
581
582
583
584
585 //IsPhysical = false;
586 base.RaiseOutOfBounds(_position);
587 _velocity.X = 0;
588 _velocity.Y = 0;
589 _velocity.Z = 0;
590 m_rotationalVelocity.X = 0;
591 m_rotationalVelocity.Y = 0;
592 m_rotationalVelocity.Z = 0;
593 base.RequestPhysicsterseUpdate();
594 m_throttleUpdates = false;
595 throttleCounter = 0;
596 _zeroFlag = true;
597 //outofBounds = true;
598 }
599
600 if ((Math.Abs(m_lastposition.X - l_position.X) < 0.02)
601 && (Math.Abs(m_lastposition.Y - l_position.Y) < 0.02)
602 && (Math.Abs(m_lastposition.Z - l_position.Z) < 0.02))
603 {
604
605 _zeroFlag = true;
606 }
607 else
608 {
609 //System.Console.WriteLine(Math.Abs(m_lastposition.X - l_position.X).ToString());
610 _zeroFlag = false;
611 }
612
613
614
615 if (_zeroFlag)
616 {
617 // Supposedly this is supposed to tell SceneObjectGroup that
618 // no more updates need to be sent..
619 // but it seems broken.
620 _velocity.X = 0.0f;
621 _velocity.Y = 0.0f;
622 _velocity.Z = 0.0f;
623 //_orientation.w = 0f;
624 //_orientation.x = 0f;
625 //_orientation.y = 0f;
626 //_orientation.z = 0f;
627 m_rotationalVelocity.X = 0;
628 m_rotationalVelocity.Y = 0;
629 m_rotationalVelocity.Z = 0;
630 if (!m_lastUpdateSent)
631 {
632 m_throttleUpdates = false;
633 throttleCounter = 0;
634 base.RequestPhysicsterseUpdate();
635 m_lastUpdateSent = true;
636 }
637
638 }
639 else
640 {
641 m_lastVelocity = _velocity;
642
643 _position = l_position;
644
645 _velocity.X = vel.X;
646 _velocity.Y = vel.Y;
647 _velocity.Z = vel.Z;
648
649 m_rotationalVelocity.X = rotvel.X;
650 m_rotationalVelocity.Y = rotvel.Y;
651 m_rotationalVelocity.Z = rotvel.Z;
652 //System.Console.WriteLine("ODE: " + m_rotationalVelocity.ToString());
653 _orientation.w = ori.W;
654 _orientation.x = ori.X;
655 _orientation.y = ori.Y;
656 _orientation.z = ori.Z;
657 m_lastUpdateSent = false;
658 if (!m_throttleUpdates || throttleCounter > 15)
659 {
660 base.RequestPhysicsterseUpdate();
661 }
662 else
663 {
664 throttleCounter++;
665 }
666 }
667 m_lastposition = l_position;
668 }
669 else
670 {
671 // Not a body.. so Make sure the client isn't interpolating
672 _velocity.X = 0;
673 _velocity.Y = 0;
674 _velocity.Z = 0;
675 m_rotationalVelocity.X = 0;
676 m_rotationalVelocity.Y = 0;
677 m_rotationalVelocity.Z = 0;
678 _zeroFlag = true;
679 }
680
681 }
682 public override void SetMomentum(PhysicsVector momentum)
683 {
684 }
685 }
686}