aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/OpenSim/Region/Physics/BulletSPlugin/BSDynamics.cs
diff options
context:
space:
mode:
Diffstat (limited to 'OpenSim/Region/Physics/BulletSPlugin/BSDynamics.cs')
-rw-r--r--OpenSim/Region/Physics/BulletSPlugin/BSDynamics.cs733
1 files changed, 472 insertions, 261 deletions
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSDynamics.cs b/OpenSim/Region/Physics/BulletSPlugin/BSDynamics.cs
index 56342b8..dbc9039 100644
--- a/OpenSim/Region/Physics/BulletSPlugin/BSDynamics.cs
+++ b/OpenSim/Region/Physics/BulletSPlugin/BSDynamics.cs
@@ -23,7 +23,7 @@
23 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 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 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. 25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */ 26 *
27 27
28/* RA: June 14, 2011. Copied from ODEDynamics.cs and converted to 28/* RA: June 14, 2011. Copied from ODEDynamics.cs and converted to
29 * call the BulletSim system. 29 * call the BulletSim system.
@@ -52,12 +52,17 @@ using OpenSim.Region.Physics.Manager;
52 52
53namespace OpenSim.Region.Physics.BulletSPlugin 53namespace OpenSim.Region.Physics.BulletSPlugin
54{ 54{
55 public class BSDynamics 55 public sealed class BSDynamics
56 { 56 {
57 private static string LogHeader = "[BULLETSIM VEHICLE]";
58
57 private BSScene PhysicsScene { get; set; } 59 private BSScene PhysicsScene { get; set; }
58 // the prim this dynamic controller belongs to 60 // the prim this dynamic controller belongs to
59 private BSPrim Prim { get; set; } 61 private BSPrim Prim { get; set; }
60 62
63 // mass of the vehicle fetched each time we're calles
64 private float m_vehicleMass;
65
61 // Vehicle properties 66 // Vehicle properties
62 public Vehicle Type { get; set; } 67 public Vehicle Type { get; set; }
63 68
@@ -72,8 +77,11 @@ namespace OpenSim.Region.Physics.BulletSPlugin
72 // LIMIT_ROLL_ONLY 77 // LIMIT_ROLL_ONLY
73 private Vector3 m_BlockingEndPoint = Vector3.Zero; 78 private Vector3 m_BlockingEndPoint = Vector3.Zero;
74 private Quaternion m_RollreferenceFrame = Quaternion.Identity; 79 private Quaternion m_RollreferenceFrame = Quaternion.Identity;
80 private Quaternion m_referenceFrame = Quaternion.Identity;
81
75 // Linear properties 82 // Linear properties
76 private Vector3 m_linearMotorDirection = Vector3.Zero; // velocity requested by LSL, decayed by time 83 private Vector3 m_linearMotorDirection = Vector3.Zero; // velocity requested by LSL, decayed by time
84 private Vector3 m_linearMotorOffset = Vector3.Zero; // the point of force can be offset from the center
77 private Vector3 m_linearMotorDirectionLASTSET = Vector3.Zero; // velocity requested by LSL 85 private Vector3 m_linearMotorDirectionLASTSET = Vector3.Zero; // velocity requested by LSL
78 private Vector3 m_newVelocity = Vector3.Zero; // velocity computed to be applied to body 86 private Vector3 m_newVelocity = Vector3.Zero; // velocity computed to be applied to body
79 private Vector3 m_linearFrictionTimescale = Vector3.Zero; 87 private Vector3 m_linearFrictionTimescale = Vector3.Zero;
@@ -86,7 +94,7 @@ namespace OpenSim.Region.Physics.BulletSPlugin
86 94
87 //Angular properties 95 //Angular properties
88 private Vector3 m_angularMotorDirection = Vector3.Zero; // angular velocity requested by LSL motor 96 private Vector3 m_angularMotorDirection = Vector3.Zero; // angular velocity requested by LSL motor
89 private int m_angularMotorApply = 0; // application frame counter 97 // private int m_angularMotorApply = 0; // application frame counter
90 private Vector3 m_angularMotorVelocity = Vector3.Zero; // current angular motor velocity 98 private Vector3 m_angularMotorVelocity = Vector3.Zero; // current angular motor velocity
91 private float m_angularMotorTimescale = 0; // motor angular velocity ramp up rate 99 private float m_angularMotorTimescale = 0; // motor angular velocity ramp up rate
92 private float m_angularMotorDecayTimescale = 0; // motor angular velocity decay rate 100 private float m_angularMotorDecayTimescale = 0; // motor angular velocity decay rate
@@ -95,19 +103,19 @@ namespace OpenSim.Region.Physics.BulletSPlugin
95 private Vector3 m_lastVertAttractor = Vector3.Zero; // what VA was last applied to body 103 private Vector3 m_lastVertAttractor = Vector3.Zero; // what VA was last applied to body
96 104
97 //Deflection properties 105 //Deflection properties
98 // private float m_angularDeflectionEfficiency = 0; 106 private float m_angularDeflectionEfficiency = 0;
99 // private float m_angularDeflectionTimescale = 0; 107 private float m_angularDeflectionTimescale = 0;
100 // private float m_linearDeflectionEfficiency = 0; 108 private float m_linearDeflectionEfficiency = 0;
101 // private float m_linearDeflectionTimescale = 0; 109 private float m_linearDeflectionTimescale = 0;
102 110
103 //Banking properties 111 //Banking properties
104 // private float m_bankingEfficiency = 0; 112 private float m_bankingEfficiency = 0;
105 // private float m_bankingMix = 0; 113 private float m_bankingMix = 0;
106 // private float m_bankingTimescale = 0; 114 private float m_bankingTimescale = 0;
107 115
108 //Hover and Buoyancy properties 116 //Hover and Buoyancy properties
109 private float m_VhoverHeight = 0f; 117 private float m_VhoverHeight = 0f;
110// private float m_VhoverEfficiency = 0f; 118 private float m_VhoverEfficiency = 0f;
111 private float m_VhoverTimescale = 0f; 119 private float m_VhoverTimescale = 0f;
112 private float m_VhoverTargetHeight = -1.0f; // if <0 then no hover, else its the current target height 120 private float m_VhoverTargetHeight = -1.0f; // if <0 then no hover, else its the current target height
113 private float m_VehicleBuoyancy = 0f; //KF: m_VehicleBuoyancy is set by VEHICLE_BUOYANCY for a vehicle. 121 private float m_VehicleBuoyancy = 0f; //KF: m_VehicleBuoyancy is set by VEHICLE_BUOYANCY for a vehicle.
@@ -138,10 +146,10 @@ namespace OpenSim.Region.Physics.BulletSPlugin
138 switch (pParam) 146 switch (pParam)
139 { 147 {
140 case Vehicle.ANGULAR_DEFLECTION_EFFICIENCY: 148 case Vehicle.ANGULAR_DEFLECTION_EFFICIENCY:
141 // m_angularDeflectionEfficiency = Math.Max(pValue, 0.01f); 149 m_angularDeflectionEfficiency = Math.Max(pValue, 0.01f);
142 break; 150 break;
143 case Vehicle.ANGULAR_DEFLECTION_TIMESCALE: 151 case Vehicle.ANGULAR_DEFLECTION_TIMESCALE:
144 // m_angularDeflectionTimescale = Math.Max(pValue, 0.01f); 152 m_angularDeflectionTimescale = Math.Max(pValue, 0.01f);
145 break; 153 break;
146 case Vehicle.ANGULAR_MOTOR_DECAY_TIMESCALE: 154 case Vehicle.ANGULAR_MOTOR_DECAY_TIMESCALE:
147 m_angularMotorDecayTimescale = Math.Max(pValue, 0.01f); 155 m_angularMotorDecayTimescale = Math.Max(pValue, 0.01f);
@@ -150,20 +158,20 @@ namespace OpenSim.Region.Physics.BulletSPlugin
150 m_angularMotorTimescale = Math.Max(pValue, 0.01f); 158 m_angularMotorTimescale = Math.Max(pValue, 0.01f);
151 break; 159 break;
152 case Vehicle.BANKING_EFFICIENCY: 160 case Vehicle.BANKING_EFFICIENCY:
153 // m_bankingEfficiency = Math.Max(pValue, 0.01f); 161 m_bankingEfficiency = Math.Max(-1f, Math.Min(pValue, 1f));
154 break; 162 break;
155 case Vehicle.BANKING_MIX: 163 case Vehicle.BANKING_MIX:
156 // m_bankingMix = Math.Max(pValue, 0.01f); 164 m_bankingMix = Math.Max(pValue, 0.01f);
157 break; 165 break;
158 case Vehicle.BANKING_TIMESCALE: 166 case Vehicle.BANKING_TIMESCALE:
159 // m_bankingTimescale = Math.Max(pValue, 0.01f); 167 m_bankingTimescale = Math.Max(pValue, 0.01f);
160 break; 168 break;
161 case Vehicle.BUOYANCY: 169 case Vehicle.BUOYANCY:
162 m_VehicleBuoyancy = Math.Max(-1f, Math.Min(pValue, 1f)); 170 m_VehicleBuoyancy = Math.Max(-1f, Math.Min(pValue, 1f));
163 break; 171 break;
164// case Vehicle.HOVER_EFFICIENCY: 172 case Vehicle.HOVER_EFFICIENCY:
165// m_VhoverEfficiency = Math.Max(0f, Math.Min(pValue, 1f)); 173 m_VhoverEfficiency = Math.Max(0f, Math.Min(pValue, 1f));
166// break; 174 break;
167 case Vehicle.HOVER_HEIGHT: 175 case Vehicle.HOVER_HEIGHT:
168 m_VhoverHeight = pValue; 176 m_VhoverHeight = pValue;
169 break; 177 break;
@@ -171,10 +179,10 @@ namespace OpenSim.Region.Physics.BulletSPlugin
171 m_VhoverTimescale = Math.Max(pValue, 0.01f); 179 m_VhoverTimescale = Math.Max(pValue, 0.01f);
172 break; 180 break;
173 case Vehicle.LINEAR_DEFLECTION_EFFICIENCY: 181 case Vehicle.LINEAR_DEFLECTION_EFFICIENCY:
174 // m_linearDeflectionEfficiency = Math.Max(pValue, 0.01f); 182 m_linearDeflectionEfficiency = Math.Max(pValue, 0.01f);
175 break; 183 break;
176 case Vehicle.LINEAR_DEFLECTION_TIMESCALE: 184 case Vehicle.LINEAR_DEFLECTION_TIMESCALE:
177 // m_linearDeflectionTimescale = Math.Max(pValue, 0.01f); 185 m_linearDeflectionTimescale = Math.Max(pValue, 0.01f);
178 break; 186 break;
179 case Vehicle.LINEAR_MOTOR_DECAY_TIMESCALE: 187 case Vehicle.LINEAR_MOTOR_DECAY_TIMESCALE:
180 m_linearMotorDecayTimescale = Math.Max(pValue, 0.01f); 188 m_linearMotorDecayTimescale = Math.Max(pValue, 0.01f);
@@ -196,7 +204,7 @@ namespace OpenSim.Region.Physics.BulletSPlugin
196 break; 204 break;
197 case Vehicle.ANGULAR_MOTOR_DIRECTION: 205 case Vehicle.ANGULAR_MOTOR_DIRECTION:
198 m_angularMotorDirection = new Vector3(pValue, pValue, pValue); 206 m_angularMotorDirection = new Vector3(pValue, pValue, pValue);
199 m_angularMotorApply = 10; 207 // m_angularMotorApply = 100;
200 break; 208 break;
201 case Vehicle.LINEAR_FRICTION_TIMESCALE: 209 case Vehicle.LINEAR_FRICTION_TIMESCALE:
202 m_linearFrictionTimescale = new Vector3(pValue, pValue, pValue); 210 m_linearFrictionTimescale = new Vector3(pValue, pValue, pValue);
@@ -206,7 +214,7 @@ namespace OpenSim.Region.Physics.BulletSPlugin
206 m_linearMotorDirectionLASTSET = new Vector3(pValue, pValue, pValue); 214 m_linearMotorDirectionLASTSET = new Vector3(pValue, pValue, pValue);
207 break; 215 break;
208 case Vehicle.LINEAR_MOTOR_OFFSET: 216 case Vehicle.LINEAR_MOTOR_OFFSET:
209 // m_linearMotorOffset = new Vector3(pValue, pValue, pValue); 217 m_linearMotorOffset = new Vector3(pValue, pValue, pValue);
210 break; 218 break;
211 219
212 } 220 }
@@ -221,15 +229,12 @@ namespace OpenSim.Region.Physics.BulletSPlugin
221 m_angularFrictionTimescale = new Vector3(pValue.X, pValue.Y, pValue.Z); 229 m_angularFrictionTimescale = new Vector3(pValue.X, pValue.Y, pValue.Z);
222 break; 230 break;
223 case Vehicle.ANGULAR_MOTOR_DIRECTION: 231 case Vehicle.ANGULAR_MOTOR_DIRECTION:
224 m_angularMotorDirection = new Vector3(pValue.X, pValue.Y, pValue.Z);
225 // Limit requested angular speed to 2 rps= 4 pi rads/sec 232 // Limit requested angular speed to 2 rps= 4 pi rads/sec
226 if (m_angularMotorDirection.X > 12.56f) m_angularMotorDirection.X = 12.56f; 233 pValue.X = Math.Max(-12.56f, Math.Min(pValue.X, 12.56f));
227 if (m_angularMotorDirection.X < - 12.56f) m_angularMotorDirection.X = - 12.56f; 234 pValue.Y = Math.Max(-12.56f, Math.Min(pValue.Y, 12.56f));
228 if (m_angularMotorDirection.Y > 12.56f) m_angularMotorDirection.Y = 12.56f; 235 pValue.Z = Math.Max(-12.56f, Math.Min(pValue.Z, 12.56f));
229 if (m_angularMotorDirection.Y < - 12.56f) m_angularMotorDirection.Y = - 12.56f; 236 m_angularMotorDirection = new Vector3(pValue.X, pValue.Y, pValue.Z);
230 if (m_angularMotorDirection.Z > 12.56f) m_angularMotorDirection.Z = 12.56f; 237 // m_angularMotorApply = 100;
231 if (m_angularMotorDirection.Z < - 12.56f) m_angularMotorDirection.Z = - 12.56f;
232 m_angularMotorApply = 10;
233 break; 238 break;
234 case Vehicle.LINEAR_FRICTION_TIMESCALE: 239 case Vehicle.LINEAR_FRICTION_TIMESCALE:
235 m_linearFrictionTimescale = new Vector3(pValue.X, pValue.Y, pValue.Z); 240 m_linearFrictionTimescale = new Vector3(pValue.X, pValue.Y, pValue.Z);
@@ -239,7 +244,7 @@ namespace OpenSim.Region.Physics.BulletSPlugin
239 m_linearMotorDirectionLASTSET = new Vector3(pValue.X, pValue.Y, pValue.Z); 244 m_linearMotorDirectionLASTSET = new Vector3(pValue.X, pValue.Y, pValue.Z);
240 break; 245 break;
241 case Vehicle.LINEAR_MOTOR_OFFSET: 246 case Vehicle.LINEAR_MOTOR_OFFSET:
242 // m_linearMotorOffset = new Vector3(pValue.X, pValue.Y, pValue.Z); 247 m_linearMotorOffset = new Vector3(pValue.X, pValue.Y, pValue.Z);
243 break; 248 break;
244 case Vehicle.BLOCK_EXIT: 249 case Vehicle.BLOCK_EXIT:
245 m_BlockingEndPoint = new Vector3(pValue.X, pValue.Y, pValue.Z); 250 m_BlockingEndPoint = new Vector3(pValue.X, pValue.Y, pValue.Z);
@@ -253,7 +258,7 @@ namespace OpenSim.Region.Physics.BulletSPlugin
253 switch (pParam) 258 switch (pParam)
254 { 259 {
255 case Vehicle.REFERENCE_FRAME: 260 case Vehicle.REFERENCE_FRAME:
256 // m_referenceFrame = pValue; 261 m_referenceFrame = pValue;
257 break; 262 break;
258 case Vehicle.ROLL_FRAME: 263 case Vehicle.ROLL_FRAME:
259 m_RollreferenceFrame = pValue; 264 m_RollreferenceFrame = pValue;
@@ -265,21 +270,16 @@ namespace OpenSim.Region.Physics.BulletSPlugin
265 { 270 {
266 VDetailLog("{0},ProcessVehicleFlags,param={1},remove={2}", Prim.LocalID, pParam, remove); 271 VDetailLog("{0},ProcessVehicleFlags,param={1},remove={2}", Prim.LocalID, pParam, remove);
267 VehicleFlag parm = (VehicleFlag)pParam; 272 VehicleFlag parm = (VehicleFlag)pParam;
268 if (remove) 273 if (pParam == -1)
274 m_flags = (VehicleFlag)0;
275 else
269 { 276 {
270 if (pParam == -1) 277 if (remove)
271 {
272 m_flags = (VehicleFlag)0;
273 }
274 else
275 {
276 m_flags &= ~parm; 278 m_flags &= ~parm;
277 } 279 else
278 } 280 m_flags |= parm;
279 else {
280 m_flags |= parm;
281 } 281 }
282 }//end ProcessVehicleFlags 282 }
283 283
284 internal void ProcessTypeChange(Vehicle pType) 284 internal void ProcessTypeChange(Vehicle pType)
285 { 285 {
@@ -288,101 +288,144 @@ namespace OpenSim.Region.Physics.BulletSPlugin
288 Type = pType; 288 Type = pType;
289 switch (pType) 289 switch (pType)
290 { 290 {
291 case Vehicle.TYPE_NONE: 291 case Vehicle.TYPE_NONE:
292 m_linearFrictionTimescale = new Vector3(0, 0, 0);
293 m_angularFrictionTimescale = new Vector3(0, 0, 0);
294 m_linearMotorDirection = Vector3.Zero; 292 m_linearMotorDirection = Vector3.Zero;
295 m_linearMotorTimescale = 0; 293 m_linearMotorTimescale = 0;
296 m_linearMotorDecayTimescale = 0; 294 m_linearMotorDecayTimescale = 0;
295 m_linearFrictionTimescale = new Vector3(0, 0, 0);
296
297 m_angularMotorDirection = Vector3.Zero; 297 m_angularMotorDirection = Vector3.Zero;
298 m_angularMotorTimescale = 0;
299 m_angularMotorDecayTimescale = 0; 298 m_angularMotorDecayTimescale = 0;
299 m_angularMotorTimescale = 0;
300 m_angularFrictionTimescale = new Vector3(0, 0, 0);
301
300 m_VhoverHeight = 0; 302 m_VhoverHeight = 0;
303 m_VhoverEfficiency = 0;
301 m_VhoverTimescale = 0; 304 m_VhoverTimescale = 0;
302 m_VehicleBuoyancy = 0; 305 m_VehicleBuoyancy = 0;
306
307 m_linearDeflectionEfficiency = 1;
308 m_linearDeflectionTimescale = 1;
309
310 m_angularDeflectionEfficiency = 0;
311 m_angularDeflectionTimescale = 1000;
312
313 m_verticalAttractionEfficiency = 0;
314 m_verticalAttractionTimescale = 0;
315
316 m_bankingEfficiency = 0;
317 m_bankingTimescale = 1000;
318 m_bankingMix = 1;
319
320 m_referenceFrame = Quaternion.Identity;
303 m_flags = (VehicleFlag)0; 321 m_flags = (VehicleFlag)0;
304 break; 322 break;
305 323
306 case Vehicle.TYPE_SLED: 324 case Vehicle.TYPE_SLED:
307 m_linearFrictionTimescale = new Vector3(30, 1, 1000);
308 m_angularFrictionTimescale = new Vector3(1000, 1000, 1000);
309 m_linearMotorDirection = Vector3.Zero; 325 m_linearMotorDirection = Vector3.Zero;
310 m_linearMotorTimescale = 1000; 326 m_linearMotorTimescale = 1000;
311 m_linearMotorDecayTimescale = 120; 327 m_linearMotorDecayTimescale = 120;
328 m_linearFrictionTimescale = new Vector3(30, 1, 1000);
329
312 m_angularMotorDirection = Vector3.Zero; 330 m_angularMotorDirection = Vector3.Zero;
313 m_angularMotorTimescale = 1000; 331 m_angularMotorTimescale = 1000;
314 m_angularMotorDecayTimescale = 120; 332 m_angularMotorDecayTimescale = 120;
333 m_angularFrictionTimescale = new Vector3(1000, 1000, 1000);
334
315 m_VhoverHeight = 0; 335 m_VhoverHeight = 0;
316// m_VhoverEfficiency = 1; 336 m_VhoverEfficiency = 10; // TODO: this looks wrong!!
317 m_VhoverTimescale = 10; 337 m_VhoverTimescale = 10;
318 m_VehicleBuoyancy = 0; 338 m_VehicleBuoyancy = 0;
319 // m_linearDeflectionEfficiency = 1; 339
320 // m_linearDeflectionTimescale = 1; 340 m_linearDeflectionEfficiency = 1;
321 // m_angularDeflectionEfficiency = 1; 341 m_linearDeflectionTimescale = 1;
322 // m_angularDeflectionTimescale = 1000; 342
323 // m_bankingEfficiency = 0; 343 m_angularDeflectionEfficiency = 1;
324 // m_bankingMix = 1; 344 m_angularDeflectionTimescale = 1000;
325 // m_bankingTimescale = 10; 345
326 // m_referenceFrame = Quaternion.Identity; 346 m_verticalAttractionEfficiency = 0;
347 m_verticalAttractionTimescale = 0;
348
349 m_bankingEfficiency = 0;
350 m_bankingTimescale = 10;
351 m_bankingMix = 1;
352
353 m_referenceFrame = Quaternion.Identity;
327 m_flags |= (VehicleFlag.NO_DEFLECTION_UP | VehicleFlag.LIMIT_ROLL_ONLY | VehicleFlag.LIMIT_MOTOR_UP); 354 m_flags |= (VehicleFlag.NO_DEFLECTION_UP | VehicleFlag.LIMIT_ROLL_ONLY | VehicleFlag.LIMIT_MOTOR_UP);
328 m_flags &= 355 m_flags &=
329 ~(VehicleFlag.HOVER_WATER_ONLY | VehicleFlag.HOVER_TERRAIN_ONLY | 356 ~(VehicleFlag.HOVER_WATER_ONLY | VehicleFlag.HOVER_TERRAIN_ONLY |
330 VehicleFlag.HOVER_GLOBAL_HEIGHT | VehicleFlag.HOVER_UP_ONLY); 357 VehicleFlag.HOVER_GLOBAL_HEIGHT | VehicleFlag.HOVER_UP_ONLY);
331 break; 358 break;
332 case Vehicle.TYPE_CAR: 359 case Vehicle.TYPE_CAR:
333 m_linearFrictionTimescale = new Vector3(100, 2, 1000);
334 m_angularFrictionTimescale = new Vector3(1000, 1000, 1000);
335 m_linearMotorDirection = Vector3.Zero; 360 m_linearMotorDirection = Vector3.Zero;
336 m_linearMotorTimescale = 1; 361 m_linearMotorTimescale = 1;
337 m_linearMotorDecayTimescale = 60; 362 m_linearMotorDecayTimescale = 60;
363 m_linearFrictionTimescale = new Vector3(100, 2, 1000);
364
338 m_angularMotorDirection = Vector3.Zero; 365 m_angularMotorDirection = Vector3.Zero;
339 m_angularMotorTimescale = 1; 366 m_angularMotorTimescale = 1;
340 m_angularMotorDecayTimescale = 0.8f; 367 m_angularMotorDecayTimescale = 0.8f;
368 m_angularFrictionTimescale = new Vector3(1000, 1000, 1000);
369
341 m_VhoverHeight = 0; 370 m_VhoverHeight = 0;
342// m_VhoverEfficiency = 0; 371 m_VhoverEfficiency = 0;
343 m_VhoverTimescale = 1000; 372 m_VhoverTimescale = 1000;
344 m_VehicleBuoyancy = 0; 373 m_VehicleBuoyancy = 0;
345 // // m_linearDeflectionEfficiency = 1; 374
346 // // m_linearDeflectionTimescale = 2; 375 m_linearDeflectionEfficiency = 1;
347 // // m_angularDeflectionEfficiency = 0; 376 m_linearDeflectionTimescale = 2;
348 // m_angularDeflectionTimescale = 10; 377
378 m_angularDeflectionEfficiency = 0;
379 m_angularDeflectionTimescale = 10;
380
349 m_verticalAttractionEfficiency = 1f; 381 m_verticalAttractionEfficiency = 1f;
350 m_verticalAttractionTimescale = 10f; 382 m_verticalAttractionTimescale = 10f;
351 // m_bankingEfficiency = -0.2f; 383
352 // m_bankingMix = 1; 384 m_bankingEfficiency = -0.2f;
353 // m_bankingTimescale = 1; 385 m_bankingMix = 1;
354 // m_referenceFrame = Quaternion.Identity; 386 m_bankingTimescale = 1;
355 m_flags |= (VehicleFlag.NO_DEFLECTION_UP 387
388 m_referenceFrame = Quaternion.Identity;
389 m_flags &= ~(VehicleFlag.HOVER_WATER_ONLY
390 | VehicleFlag.HOVER_TERRAIN_ONLY
391 | VehicleFlag.HOVER_GLOBAL_HEIGHT);
392 m_flags |= (VehicleFlag.NO_DEFLECTION_UP
356 | VehicleFlag.LIMIT_ROLL_ONLY 393 | VehicleFlag.LIMIT_ROLL_ONLY
357 | VehicleFlag.LIMIT_MOTOR_UP); 394 | VehicleFlag.LIMIT_MOTOR_UP
358 m_flags &= ~(VehicleFlag.HOVER_WATER_ONLY | VehicleFlag.HOVER_TERRAIN_ONLY | VehicleFlag.HOVER_GLOBAL_HEIGHT); 395 | VehicleFlag.HOVER_UP_ONLY);
359 m_flags |= (VehicleFlag.HOVER_UP_ONLY);
360 break; 396 break;
361 case Vehicle.TYPE_BOAT: 397 case Vehicle.TYPE_BOAT:
362 m_linearFrictionTimescale = new Vector3(10, 3, 2);
363 m_angularFrictionTimescale = new Vector3(10,10,10);
364 m_linearMotorDirection = Vector3.Zero; 398 m_linearMotorDirection = Vector3.Zero;
365 m_linearMotorTimescale = 5; 399 m_linearMotorTimescale = 5;
366 m_linearMotorDecayTimescale = 60; 400 m_linearMotorDecayTimescale = 60;
401 m_linearFrictionTimescale = new Vector3(10, 3, 2);
402
367 m_angularMotorDirection = Vector3.Zero; 403 m_angularMotorDirection = Vector3.Zero;
368 m_angularMotorTimescale = 4; 404 m_angularMotorTimescale = 4;
369 m_angularMotorDecayTimescale = 4; 405 m_angularMotorDecayTimescale = 4;
406 m_angularFrictionTimescale = new Vector3(10,10,10);
407
370 m_VhoverHeight = 0; 408 m_VhoverHeight = 0;
371// m_VhoverEfficiency = 0.5f; 409 m_VhoverEfficiency = 0.5f;
372 m_VhoverTimescale = 2; 410 m_VhoverTimescale = 2;
373 m_VehicleBuoyancy = 1; 411 m_VehicleBuoyancy = 1;
374 // m_linearDeflectionEfficiency = 0.5f; 412
375 // m_linearDeflectionTimescale = 3; 413 m_linearDeflectionEfficiency = 0.5f;
376 // m_angularDeflectionEfficiency = 0.5f; 414 m_linearDeflectionTimescale = 3;
377 // m_angularDeflectionTimescale = 5; 415
416 m_angularDeflectionEfficiency = 0.5f;
417 m_angularDeflectionTimescale = 5;
418
378 m_verticalAttractionEfficiency = 0.5f; 419 m_verticalAttractionEfficiency = 0.5f;
379 m_verticalAttractionTimescale = 5f; 420 m_verticalAttractionTimescale = 5f;
380 // m_bankingEfficiency = -0.3f; 421
381 // m_bankingMix = 0.8f; 422 m_bankingEfficiency = -0.3f;
382 // m_bankingTimescale = 1; 423 m_bankingMix = 0.8f;
383 // m_referenceFrame = Quaternion.Identity; 424 m_bankingTimescale = 1;
425
426 m_referenceFrame = Quaternion.Identity;
384 m_flags &= ~(VehicleFlag.HOVER_TERRAIN_ONLY 427 m_flags &= ~(VehicleFlag.HOVER_TERRAIN_ONLY
385 | VehicleFlag.HOVER_GLOBAL_HEIGHT 428 | VehicleFlag.HOVER_GLOBAL_HEIGHT
386 | VehicleFlag.LIMIT_ROLL_ONLY 429 | VehicleFlag.LIMIT_ROLL_ONLY
387 | VehicleFlag.HOVER_UP_ONLY); 430 | VehicleFlag.HOVER_UP_ONLY);
388 m_flags |= (VehicleFlag.NO_DEFLECTION_UP 431 m_flags |= (VehicleFlag.NO_DEFLECTION_UP
@@ -390,28 +433,35 @@ namespace OpenSim.Region.Physics.BulletSPlugin
390 | VehicleFlag.HOVER_WATER_ONLY); 433 | VehicleFlag.HOVER_WATER_ONLY);
391 break; 434 break;
392 case Vehicle.TYPE_AIRPLANE: 435 case Vehicle.TYPE_AIRPLANE:
393 m_linearFrictionTimescale = new Vector3(200, 10, 5);
394 m_angularFrictionTimescale = new Vector3(20, 20, 20);
395 m_linearMotorDirection = Vector3.Zero; 436 m_linearMotorDirection = Vector3.Zero;
396 m_linearMotorTimescale = 2; 437 m_linearMotorTimescale = 2;
397 m_linearMotorDecayTimescale = 60; 438 m_linearMotorDecayTimescale = 60;
439 m_linearFrictionTimescale = new Vector3(200, 10, 5);
440
398 m_angularMotorDirection = Vector3.Zero; 441 m_angularMotorDirection = Vector3.Zero;
399 m_angularMotorTimescale = 4; 442 m_angularMotorTimescale = 4;
400 m_angularMotorDecayTimescale = 4; 443 m_angularMotorDecayTimescale = 4;
444 m_angularFrictionTimescale = new Vector3(20, 20, 20);
445
401 m_VhoverHeight = 0; 446 m_VhoverHeight = 0;
402// m_VhoverEfficiency = 0.5f; 447 m_VhoverEfficiency = 0.5f;
403 m_VhoverTimescale = 1000; 448 m_VhoverTimescale = 1000;
404 m_VehicleBuoyancy = 0; 449 m_VehicleBuoyancy = 0;
405 // m_linearDeflectionEfficiency = 0.5f; 450
406 // m_linearDeflectionTimescale = 3; 451 m_linearDeflectionEfficiency = 0.5f;
407 // m_angularDeflectionEfficiency = 1; 452 m_linearDeflectionTimescale = 3;
408 // m_angularDeflectionTimescale = 2; 453
454 m_angularDeflectionEfficiency = 1;
455 m_angularDeflectionTimescale = 2;
456
409 m_verticalAttractionEfficiency = 0.9f; 457 m_verticalAttractionEfficiency = 0.9f;
410 m_verticalAttractionTimescale = 2f; 458 m_verticalAttractionTimescale = 2f;
411 // m_bankingEfficiency = 1; 459
412 // m_bankingMix = 0.7f; 460 m_bankingEfficiency = 1;
413 // m_bankingTimescale = 2; 461 m_bankingMix = 0.7f;
414 // m_referenceFrame = Quaternion.Identity; 462 m_bankingTimescale = 2;
463
464 m_referenceFrame = Quaternion.Identity;
415 m_flags &= ~(VehicleFlag.HOVER_WATER_ONLY 465 m_flags &= ~(VehicleFlag.HOVER_WATER_ONLY
416 | VehicleFlag.HOVER_TERRAIN_ONLY 466 | VehicleFlag.HOVER_TERRAIN_ONLY
417 | VehicleFlag.HOVER_GLOBAL_HEIGHT 467 | VehicleFlag.HOVER_GLOBAL_HEIGHT
@@ -421,28 +471,36 @@ namespace OpenSim.Region.Physics.BulletSPlugin
421 m_flags |= (VehicleFlag.LIMIT_ROLL_ONLY); 471 m_flags |= (VehicleFlag.LIMIT_ROLL_ONLY);
422 break; 472 break;
423 case Vehicle.TYPE_BALLOON: 473 case Vehicle.TYPE_BALLOON:
424 m_linearFrictionTimescale = new Vector3(5, 5, 5);
425 m_angularFrictionTimescale = new Vector3(10, 10, 10);
426 m_linearMotorDirection = Vector3.Zero; 474 m_linearMotorDirection = Vector3.Zero;
427 m_linearMotorTimescale = 5; 475 m_linearMotorTimescale = 5;
476 m_linearFrictionTimescale = new Vector3(5, 5, 5);
428 m_linearMotorDecayTimescale = 60; 477 m_linearMotorDecayTimescale = 60;
478
429 m_angularMotorDirection = Vector3.Zero; 479 m_angularMotorDirection = Vector3.Zero;
430 m_angularMotorTimescale = 6; 480 m_angularMotorTimescale = 6;
481 m_angularFrictionTimescale = new Vector3(10, 10, 10);
431 m_angularMotorDecayTimescale = 10; 482 m_angularMotorDecayTimescale = 10;
483
432 m_VhoverHeight = 5; 484 m_VhoverHeight = 5;
433// m_VhoverEfficiency = 0.8f; 485 m_VhoverEfficiency = 0.8f;
434 m_VhoverTimescale = 10; 486 m_VhoverTimescale = 10;
435 m_VehicleBuoyancy = 1; 487 m_VehicleBuoyancy = 1;
436 // m_linearDeflectionEfficiency = 0; 488
437 // m_linearDeflectionTimescale = 5; 489 m_linearDeflectionEfficiency = 0;
438 // m_angularDeflectionEfficiency = 0; 490 m_linearDeflectionTimescale = 5;
439 // m_angularDeflectionTimescale = 5; 491
492 m_angularDeflectionEfficiency = 0;
493 m_angularDeflectionTimescale = 5;
494
440 m_verticalAttractionEfficiency = 1f; 495 m_verticalAttractionEfficiency = 1f;
441 m_verticalAttractionTimescale = 100f; 496 m_verticalAttractionTimescale = 100f;
442 // m_bankingEfficiency = 0; 497
443 // m_bankingMix = 0.7f; 498 m_bankingEfficiency = 0;
444 // m_bankingTimescale = 5; 499 m_bankingMix = 0.7f;
445 // m_referenceFrame = Quaternion.Identity; 500 m_bankingTimescale = 5;
501 m_referenceFrame = Quaternion.Identity;
502
503 m_referenceFrame = Quaternion.Identity;
446 m_flags &= ~(VehicleFlag.HOVER_WATER_ONLY 504 m_flags &= ~(VehicleFlag.HOVER_WATER_ONLY
447 | VehicleFlag.HOVER_TERRAIN_ONLY 505 | VehicleFlag.HOVER_TERRAIN_ONLY
448 | VehicleFlag.HOVER_UP_ONLY 506 | VehicleFlag.HOVER_UP_ONLY
@@ -452,20 +510,40 @@ namespace OpenSim.Region.Physics.BulletSPlugin
452 | VehicleFlag.HOVER_GLOBAL_HEIGHT); 510 | VehicleFlag.HOVER_GLOBAL_HEIGHT);
453 break; 511 break;
454 } 512 }
455 }//end SetDefaultsForType 513 }
456 514
457 // Some of the properties of this prim may have changed. 515 // Some of the properties of this prim may have changed.
458 // Do any updating needed for a vehicle 516 // Do any updating needed for a vehicle
459 public void Refresh() 517 public void Refresh()
460 { 518 {
461 if (!IsActive) 519 if (IsActive)
462 return; 520 {
521 // Friction effects are handled by this vehicle code
522 BulletSimAPI.SetFriction2(Prim.PhysBody.ptr, 0f);
523 BulletSimAPI.SetHitFraction2(Prim.PhysBody.ptr, 0f);
524
525 // BulletSimAPI.SetAngularDamping2(Prim.PhysBody.ptr, 0.8f);
463 526
464 // Set the prim's inertia to zero. The vehicle code handles that and this 527 VDetailLog("{0},BSDynamics.Refresh,zeroingFriction and adding damping", Prim.LocalID);
465 // removes the motion and torque actions introduced by Bullet. 528 }
466 Vector3 inertia = Vector3.Zero; 529 }
467 BulletSimAPI.SetMassProps2(Prim.BSBody.ptr, Prim.MassRaw, inertia); 530
468 BulletSimAPI.UpdateInertiaTensor2(Prim.BSBody.ptr); 531 public bool RemoveBodyDependencies(BSPhysObject prim)
532 {
533 // If active, we need to add our properties back when the body is rebuilt.
534 return IsActive;
535 }
536
537 public void RestoreBodyDependencies(BSPhysObject prim)
538 {
539 if (Prim.LocalID != prim.LocalID)
540 {
541 // The call should be on us by our prim. Error if not.
542 PhysicsScene.Logger.ErrorFormat("{0} RestoreBodyDependencies: called by not my prim. passedLocalID={1}, vehiclePrimLocalID={2}",
543 LogHeader, prim.LocalID, Prim.LocalID);
544 return;
545 }
546 Refresh();
469 } 547 }
470 548
471 // One step of the vehicle properties for the next 'pTimestep' seconds. 549 // One step of the vehicle properties for the next 'pTimestep' seconds.
@@ -473,13 +551,35 @@ namespace OpenSim.Region.Physics.BulletSPlugin
473 { 551 {
474 if (!IsActive) return; 552 if (!IsActive) return;
475 553
554 // DEBUG
555 // Because Bullet does apply forces to the vehicle, our last computed
556 // linear and angular velocities are not what is happening now.
557 // Vector3 externalAngularVelocity = Prim.ForceRotationalVelocity - m_lastAngularVelocity;
558 // m_lastAngularVelocity += (externalAngularVelocity * 0.5f) * pTimestep;
559 // m_lastAngularVelocity = Prim.ForceRotationalVelocity; // DEBUG: account for what Bullet did last time
560 // m_lastLinearVelocityVector = Prim.ForceVelocity * Quaternion.Inverse(Prim.ForceOrientation); // DEBUG:
561 // END DEBUG
562
563 m_vehicleMass = Prim.Linkset.LinksetMass;
564
476 MoveLinear(pTimestep); 565 MoveLinear(pTimestep);
566 // Commented out for debug
477 MoveAngular(pTimestep); 567 MoveAngular(pTimestep);
568 // Prim.ApplyTorqueImpulse(-Prim.RotationalVelocity * m_vehicleMass, false); // DEBUG DEBUG
569 // Prim.ForceRotationalVelocity = -Prim.RotationalVelocity; // DEBUG DEBUG
570
478 LimitRotation(pTimestep); 571 LimitRotation(pTimestep);
479 572
480 // remember the position so next step we can limit absolute movement effects 573 // remember the position so next step we can limit absolute movement effects
481 m_lastPositionVector = Prim.ForcePosition; 574 m_lastPositionVector = Prim.ForcePosition;
482 575
576 VDetailLog("{0},BSDynamics.Step,frict={1},grav={2},inertia={3},mass={4}", // DEBUG DEBUG
577 Prim.LocalID,
578 BulletSimAPI.GetFriction2(Prim.PhysBody.ptr),
579 BulletSimAPI.GetGravity2(Prim.PhysBody.ptr),
580 Prim.Inertia,
581 m_vehicleMass
582 );
483 VDetailLog("{0},BSDynamics.Step,done,pos={1},force={2},velocity={3},angvel={4}", 583 VDetailLog("{0},BSDynamics.Step,done,pos={1},force={2},velocity={3},angvel={4}",
484 Prim.LocalID, Prim.ForcePosition, Prim.Force, Prim.ForceVelocity, Prim.RotationalVelocity); 584 Prim.LocalID, Prim.ForcePosition, Prim.Force, Prim.ForceVelocity, Prim.RotationalVelocity);
485 }// end Step 585 }// end Step
@@ -488,62 +588,52 @@ namespace OpenSim.Region.Physics.BulletSPlugin
488 // Also does hover and float. 588 // Also does hover and float.
489 private void MoveLinear(float pTimestep) 589 private void MoveLinear(float pTimestep)
490 { 590 {
491 // m_linearMotorDirection is the direction we are moving relative to the vehicle coordinates 591 // m_linearMotorDirection is the target direction we are moving relative to the vehicle coordinates
492 // m_lastLinearVelocityVector is the speed we are moving in that direction 592 // m_lastLinearVelocityVector is the current speed we are moving in that direction
493 if (m_linearMotorDirection.LengthSquared() > 0.001f) 593 if (m_linearMotorDirection.LengthSquared() > 0.001f)
494 { 594 {
495 Vector3 origDir = m_linearMotorDirection; 595 Vector3 origDir = m_linearMotorDirection; // DEBUG
496 Vector3 origVel = m_lastLinearVelocityVector; 596 Vector3 origVel = m_lastLinearVelocityVector; // DEBUG
497 597 // DEBUG: the vehicle velocity rotated to be relative to vehicle coordinates for comparison
498 // add drive to body 598 Vector3 vehicleVelocity = Prim.ForceVelocity * Quaternion.Inverse(Prim.ForceOrientation); // DEBUG
499 // Vector3 addAmount = m_linearMotorDirection/(m_linearMotorTimescale / pTimestep); 599
500 Vector3 addAmount = (m_linearMotorDirection - m_lastLinearVelocityVector)/(m_linearMotorTimescale / pTimestep); 600 // Add (desiredVelocity - lastAppliedVelocity) / howLongItShouldTakeToComplete
501 // lastLinearVelocityVector is the current body velocity vector 601 Vector3 addAmount = (m_linearMotorDirection - m_lastLinearVelocityVector)/(m_linearMotorTimescale) * pTimestep;
502 // RA: Not sure what the *10 is for. A correction for pTimestep?
503 // m_lastLinearVelocityVector += (addAmount*10);
504 m_lastLinearVelocityVector += addAmount; 602 m_lastLinearVelocityVector += addAmount;
505 603
506 // Limit the velocity vector to less than the last set linear motor direction 604 float decayFactor = (1.0f / m_linearMotorDecayTimescale) * pTimestep;
507 if (Math.Abs(m_lastLinearVelocityVector.X) > Math.Abs(m_linearMotorDirectionLASTSET.X)) 605 m_linearMotorDirection *= (1f - decayFactor);
508 m_lastLinearVelocityVector.X = m_linearMotorDirectionLASTSET.X; 606
509 if (Math.Abs(m_lastLinearVelocityVector.Y) > Math.Abs(m_linearMotorDirectionLASTSET.Y)) 607 // Rotate new object velocity from vehicle relative to world coordinates
510 m_lastLinearVelocityVector.Y = m_linearMotorDirectionLASTSET.Y; 608 m_newVelocity = m_lastLinearVelocityVector * Prim.ForceOrientation;
511 if (Math.Abs(m_lastLinearVelocityVector.Z) > Math.Abs(m_linearMotorDirectionLASTSET.Z)) 609
512 m_lastLinearVelocityVector.Z = m_linearMotorDirectionLASTSET.Z; 610 // Apply friction for next time
513 611 Vector3 frictionFactor = (Vector3.One / m_linearFrictionTimescale) * pTimestep;
514 /* 612 m_lastLinearVelocityVector *= (Vector3.One - frictionFactor);
515 // decay applied velocity 613
516 Vector3 decayfraction = Vector3.One/(m_linearMotorDecayTimescale / pTimestep); 614 VDetailLog("{0},MoveLinear,nonZero,origlmDir={1},origlvVel={2},vehVel={3},add={4},decay={5},frict={6},lmDir={7},lvVec={8},newVel={9}",
517 // (RA: do not know where the 0.5f comes from) 615 Prim.LocalID, origDir, origVel, vehicleVelocity, addAmount, decayFactor, frictionFactor,
518 m_linearMotorDirection -= m_linearMotorDirection * decayfraction * 0.5f; 616 m_linearMotorDirection, m_lastLinearVelocityVector, m_newVelocity);
519 */
520 float keepfraction = 1.0f - (1.0f / (m_linearMotorDecayTimescale / pTimestep));
521 m_linearMotorDirection *= keepfraction;
522
523 VDetailLog("{0},MoveLinear,nonZero,origdir={1},origvel={2},add={3},notDecay={4},dir={5},vel={6}",
524 Prim.LocalID, origDir, origVel, addAmount, keepfraction, m_linearMotorDirection, m_lastLinearVelocityVector);
525 } 617 }
526 else 618 else
527 { 619 {
528 // if what remains of direction is very small, zero it. 620 // if what remains of direction is very small, zero it.
529 m_linearMotorDirection = Vector3.Zero; 621 m_linearMotorDirection = Vector3.Zero;
530 m_lastLinearVelocityVector = Vector3.Zero; 622 m_lastLinearVelocityVector = Vector3.Zero;
623 m_newVelocity = Vector3.Zero;
624
531 VDetailLog("{0},MoveLinear,zeroed", Prim.LocalID); 625 VDetailLog("{0},MoveLinear,zeroed", Prim.LocalID);
532 } 626 }
533 627
534 // convert requested object velocity to object relative vector 628 // m_newVelocity is velocity computed from linear motor in world coordinates
535 Quaternion rotq = Prim.ForceOrientation;
536 m_newVelocity = m_lastLinearVelocityVector * rotq;
537
538 // Add the various forces into m_dir which will be our new direction vector (velocity)
539 629
540 // add Gravity and Buoyancy 630 // Gravity and Buoyancy
541 // There is some gravity, make a gravity force vector that is applied after object velocity. 631 // There is some gravity, make a gravity force vector that is applied after object velocity.
542 // m_VehicleBuoyancy: -1=2g; 0=1g; 1=0g; 632 // m_VehicleBuoyancy: -1=2g; 0=1g; 1=0g;
543 Vector3 grav = Prim.PhysicsScene.DefaultGravity * (Prim.Linkset.LinksetMass * (1f - m_VehicleBuoyancy)); 633 Vector3 grav = Prim.PhysicsScene.DefaultGravity * (1f - m_VehicleBuoyancy);
544 634
545 /* 635 /*
546 * RA: Not sure why one would do this 636 * RA: Not sure why one would do this unless we are hoping external forces are doing gravity, ...
547 // Preserve the current Z velocity 637 // Preserve the current Z velocity
548 Vector3 vel_now = m_prim.Velocity; 638 Vector3 vel_now = m_prim.Velocity;
549 m_dir.Z = vel_now.Z; // Preserve the accumulated falling velocity 639 m_dir.Z = vel_now.Z; // Preserve the accumulated falling velocity
@@ -555,7 +645,7 @@ namespace OpenSim.Region.Physics.BulletSPlugin
555 // If below the terrain, move us above the ground a little. 645 // If below the terrain, move us above the ground a little.
556 float terrainHeight = Prim.PhysicsScene.TerrainManager.GetTerrainHeightAtXYZ(pos); 646 float terrainHeight = Prim.PhysicsScene.TerrainManager.GetTerrainHeightAtXYZ(pos);
557 // Taking the rotated size doesn't work here because m_prim.Size is the size of the root prim and not the linkset. 647 // Taking the rotated size doesn't work here because m_prim.Size is the size of the root prim and not the linkset.
558 // Need to add a m_prim.LinkSet.Size similar to m_prim.LinkSet.Mass. 648 // TODO: Add a m_prim.LinkSet.Size similar to m_prim.LinkSet.Mass.
559 // Vector3 rotatedSize = m_prim.Size * m_prim.ForceOrientation; 649 // Vector3 rotatedSize = m_prim.Size * m_prim.ForceOrientation;
560 // if (rotatedSize.Z < terrainHeight) 650 // if (rotatedSize.Z < terrainHeight)
561 if (pos.Z < terrainHeight) 651 if (pos.Z < terrainHeight)
@@ -566,6 +656,8 @@ namespace OpenSim.Region.Physics.BulletSPlugin
566 } 656 }
567 657
568 // Check if hovering 658 // Check if hovering
659 // m_VhoverEfficiency: 0=bouncy, 1=totally damped
660 // m_VhoverTimescale: time to achieve height
569 if ((m_flags & (VehicleFlag.HOVER_WATER_ONLY | VehicleFlag.HOVER_TERRAIN_ONLY | VehicleFlag.HOVER_GLOBAL_HEIGHT)) != 0) 661 if ((m_flags & (VehicleFlag.HOVER_WATER_ONLY | VehicleFlag.HOVER_TERRAIN_ONLY | VehicleFlag.HOVER_GLOBAL_HEIGHT)) != 0)
570 { 662 {
571 // We should hover, get the target height 663 // We should hover, get the target height
@@ -584,25 +676,33 @@ namespace OpenSim.Region.Physics.BulletSPlugin
584 676
585 if ((m_flags & VehicleFlag.HOVER_UP_ONLY) != 0) 677 if ((m_flags & VehicleFlag.HOVER_UP_ONLY) != 0)
586 { 678 {
587 // If body is aready heigher, use its height as target height 679 // If body is already heigher, use its height as target height
588 if (pos.Z > m_VhoverTargetHeight) m_VhoverTargetHeight = pos.Z; 680 if (pos.Z > m_VhoverTargetHeight)
681 m_VhoverTargetHeight = pos.Z;
589 } 682 }
590 if ((m_flags & VehicleFlag.LOCK_HOVER_HEIGHT) != 0) 683 if ((m_flags & VehicleFlag.LOCK_HOVER_HEIGHT) != 0)
591 { 684 {
592 if ((pos.Z - m_VhoverTargetHeight) > .2 || (pos.Z - m_VhoverTargetHeight) < -.2) 685 if (Math.Abs(pos.Z - m_VhoverTargetHeight) > 0.2f)
593 { 686 {
687 pos.Z = m_VhoverTargetHeight;
594 Prim.ForcePosition = pos; 688 Prim.ForcePosition = pos;
595 } 689 }
596 } 690 }
597 else 691 else
598 { 692 {
599 float herr0 = pos.Z - m_VhoverTargetHeight; 693 float verticalError = pos.Z - m_VhoverTargetHeight;
694 // RA: where does the 50 come from?
695 float verticalCorrectionVelocity = pTimestep * ((verticalError * 50.0f) / m_VhoverTimescale);
600 // Replace Vertical speed with correction figure if significant 696 // Replace Vertical speed with correction figure if significant
601 if (Math.Abs(herr0) > 0.01f) 697 if (Math.Abs(verticalError) > 0.01f)
602 { 698 {
603 m_newVelocity.Z = -((herr0 * pTimestep * 50.0f) / m_VhoverTimescale); 699 m_newVelocity.Z += verticalCorrectionVelocity;
604 //KF: m_VhoverEfficiency is not yet implemented 700 //KF: m_VhoverEfficiency is not yet implemented
605 } 701 }
702 else if (verticalError < -0.01)
703 {
704 m_newVelocity.Z -= verticalCorrectionVelocity;
705 }
606 else 706 else
607 { 707 {
608 m_newVelocity.Z = 0f; 708 m_newVelocity.Z = 0f;
@@ -649,25 +749,28 @@ namespace OpenSim.Region.Physics.BulletSPlugin
649 } 749 }
650 } 750 }
651 751
652 // Limit absolute vertical change 752 #region downForce
653 float Zchange = Math.Abs(posChange.Z); 753 Vector3 downForce = Vector3.Zero;
754
654 if ((m_flags & (VehicleFlag.LIMIT_MOTOR_UP)) != 0) 755 if ((m_flags & (VehicleFlag.LIMIT_MOTOR_UP)) != 0)
655 { 756 {
656 if (Zchange > .3) 757 // If the vehicle is motoring into the sky, get it going back down.
657 grav.Z = (float)(grav.Z * 3); 758 // Is this an angular force or both linear and angular??
658 if (Zchange > .15) 759 float distanceAboveGround = pos.Z - terrainHeight;
659 grav.Z = (float)(grav.Z * 2); 760 if (distanceAboveGround > 2f)
660 if (Zchange > .75) 761 {
661 grav.Z = (float)(grav.Z * 1.5); 762 // downForce = new Vector3(0, 0, (-distanceAboveGround / m_bankingTimescale) * pTimestep);
662 if (Zchange > .05) 763 // downForce = new Vector3(0, 0, -distanceAboveGround / m_bankingTimescale);
663 grav.Z = (float)(grav.Z * 1.25); 764 downForce = new Vector3(0, 0, -distanceAboveGround);
664 if (Zchange > .025) 765 }
665 grav.Z = (float)(grav.Z * 1.125); 766 // TODO: this calculation is all wrong. From the description at
666 float postemp = (pos.Z - terrainHeight); 767 // (http://wiki.secondlife.com/wiki/Category:LSL_Vehicle), the downForce
667 if (postemp > 2.5f) 768 // has a decay factor. This says this force should
668 grav.Z = (float)(grav.Z * 1.037125); 769 // be computed with a motor.
669 VDetailLog("{0},MoveLinear,limitMotorUp,grav={1}", Prim.LocalID, grav); 770 VDetailLog("{0},MoveLinear,limitMotorUp,distAbove={1},downForce={2}",
771 Prim.LocalID, distanceAboveGround, downForce);
670 } 772 }
773 #endregion // downForce
671 774
672 // If not changing some axis, reduce out velocity 775 // If not changing some axis, reduce out velocity
673 if ((m_flags & (VehicleFlag.NO_X)) != 0) 776 if ((m_flags & (VehicleFlag.NO_X)) != 0)
@@ -677,21 +780,32 @@ namespace OpenSim.Region.Physics.BulletSPlugin
677 if ((m_flags & (VehicleFlag.NO_Z)) != 0) 780 if ((m_flags & (VehicleFlag.NO_Z)) != 0)
678 m_newVelocity.Z = 0; 781 m_newVelocity.Z = 0;
679 782
680 // Apply velocity 783 // Clamp REALLY high or low velocities
784 if (m_newVelocity.LengthSquared() > 1e6f)
785 {
786 m_newVelocity /= m_newVelocity.Length();
787 m_newVelocity *= 1000f;
788 }
789 else if (m_newVelocity.LengthSquared() < 1e-6f)
790 m_newVelocity = Vector3.Zero;
791
792 // Stuff new linear velocity into the vehicle
681 Prim.ForceVelocity = m_newVelocity; 793 Prim.ForceVelocity = m_newVelocity;
682 // apply gravity force 794 // Prim.ApplyForceImpulse((m_newVelocity - Prim.Velocity) * m_vehicleMass, false); // DEBUG DEBUG
683 // Why is this set here? The physics engine already does gravity.
684 Prim.AddForce(grav, false, true);
685 795
686 // Apply friction 796 Vector3 totalDownForce = downForce + grav;
687 Vector3 keepFraction = Vector3.One - (Vector3.One / (m_linearFrictionTimescale / pTimestep)); 797 if (totalDownForce != Vector3.Zero)
688 m_lastLinearVelocityVector *= keepFraction; 798 {
799 Prim.AddForce(totalDownForce * m_vehicleMass, false);
800 // Prim.ApplyForceImpulse(totalDownForce * m_vehicleMass, false);
801 }
689 802
690 VDetailLog("{0},MoveLinear,done,lmDir={1},lmVel={2},newVel={3},grav={4},1Mdecay={5}", 803 VDetailLog("{0},MoveLinear,done,lmDir={1},lmVel={2},newVel={3},primVel={4},totalDown={5}",
691 Prim.LocalID, m_linearMotorDirection, m_lastLinearVelocityVector, m_newVelocity, grav, keepFraction); 804 Prim.LocalID, m_linearMotorDirection, m_lastLinearVelocityVector, m_newVelocity, Prim.Velocity, totalDownForce);
692 805
693 } // end MoveLinear() 806 } // end MoveLinear()
694 807
808 // =======================================================================
695 // Apply the effect of the angular motor. 809 // Apply the effect of the angular motor.
696 private void MoveAngular(float pTimestep) 810 private void MoveAngular(float pTimestep)
697 { 811 {
@@ -703,95 +817,191 @@ namespace OpenSim.Region.Physics.BulletSPlugin
703 // m_angularFrictionTimescale // body angular velocity decay rate 817 // m_angularFrictionTimescale // body angular velocity decay rate
704 // m_lastAngularVelocity // what was last applied to body 818 // m_lastAngularVelocity // what was last applied to body
705 819
706 // Get what the body is doing, this includes 'external' influences 820 if (m_angularMotorDirection.LengthSquared() > 0.0001)
707 Vector3 angularVelocity = Prim.ForceRotationalVelocity;
708
709 if (m_angularMotorApply > 0)
710 { 821 {
711 // Rather than snapping the angular motor velocity from the old value to
712 // a newly set velocity, this routine steps the value from the previous
713 // value (m_angularMotorVelocity) to the requested value (m_angularMotorDirection).
714 // There are m_angularMotorApply steps.
715 Vector3 origVel = m_angularMotorVelocity; 822 Vector3 origVel = m_angularMotorVelocity;
716 Vector3 origDir = m_angularMotorDirection; 823 Vector3 origDir = m_angularMotorDirection;
717 824
718 // ramp up to new value 825 // new velocity += error / ( time to get there / step interval)
719 // new velocity += error / ( time to get there / step interval) 826 // requested direction - current vehicle direction
720 // requested speed - last motor speed 827 m_angularMotorVelocity += (m_angularMotorDirection - m_angularMotorVelocity) / (m_angularMotorTimescale / pTimestep);
721 m_angularMotorVelocity.X += (m_angularMotorDirection.X - m_angularMotorVelocity.X) / (m_angularMotorTimescale / pTimestep); 828 // decay requested direction
722 m_angularMotorVelocity.Y += (m_angularMotorDirection.Y - m_angularMotorVelocity.Y) / (m_angularMotorTimescale / pTimestep); 829 m_angularMotorDirection *= (1.0f - (pTimestep * 1.0f/m_angularMotorDecayTimescale));
723 m_angularMotorVelocity.Z += (m_angularMotorDirection.Z - m_angularMotorVelocity.Z) / (m_angularMotorTimescale / pTimestep);
724
725 VDetailLog("{0},MoveAngular,angularMotorApply,apply={1},angTScale={2},timeStep={3},origvel={4},origDir={5},vel={6}",
726 Prim.LocalID, m_angularMotorApply, m_angularMotorTimescale, pTimestep, origVel, origDir, m_angularMotorVelocity);
727 830
728 m_angularMotorApply--; 831 VDetailLog("{0},MoveAngular,angularMotorApply,angTScale={1},timeStep={2},origvel={3},origDir={4},vel={5}",
832 Prim.LocalID, m_angularMotorTimescale, pTimestep, origVel, origDir, m_angularMotorVelocity);
729 } 833 }
730 else 834 else
731 { 835 {
732 // No motor recently applied, keep the body velocity 836 m_angularMotorVelocity = Vector3.Zero;
733 // and decay the velocity 837 }
734 m_angularMotorVelocity -= m_angularMotorVelocity / (m_angularMotorDecayTimescale / pTimestep); 838
735 if (m_angularMotorVelocity.LengthSquared() < 0.00001) 839 #region Vertical attactor
736 m_angularMotorVelocity = Vector3.Zero; 840
737 } // end motor section
738
739 // Vertical attractor section
740 Vector3 vertattr = Vector3.Zero; 841 Vector3 vertattr = Vector3.Zero;
741 Vector3 deflection = Vector3.Zero; 842 Vector3 deflection = Vector3.Zero;
742 Vector3 banking = Vector3.Zero; 843 Vector3 banking = Vector3.Zero;
743 844
845 // If vertical attaction timescale is reasonable and we applied an angular force last time...
744 if (m_verticalAttractionTimescale < 300 && m_lastAngularVelocity != Vector3.Zero) 846 if (m_verticalAttractionTimescale < 300 && m_lastAngularVelocity != Vector3.Zero)
745 { 847 {
746 float VAservo = 0.2f / (m_verticalAttractionTimescale / pTimestep); 848 float VAservo = pTimestep * 0.2f / m_verticalAttractionTimescale;
747 VAservo *= (m_verticalAttractionEfficiency * m_verticalAttractionEfficiency); 849 if (Prim.IsColliding)
850 VAservo = pTimestep * 0.05f / (m_verticalAttractionTimescale);
748 851
749 // get present body rotation 852 VAservo *= (m_verticalAttractionEfficiency * m_verticalAttractionEfficiency);
750 Quaternion rotq = Prim.ForceOrientation;
751 // vector pointing up
752 Vector3 verterr = Vector3.Zero;
753 verterr.Z = 1.0f;
754 853
755 // rotate it to Body Angle 854 // Create a vector of the vehicle "up" in world coordinates
756 verterr = verterr * rotq; 855 Vector3 verticalError = Vector3.UnitZ * Prim.ForceOrientation;
757 // verterr.X and .Y are the World error amounts. They are 0 when there is no error (Vehicle Body is 'vertical'), and .Z will be 1. 856 // verticalError.X and .Y are the World error amounts. They are 0 when there is no
758 // 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 857 // error (Vehicle Body is 'vertical'), and .Z will be 1. As the body leans to its
759 // negative. Similar for tilt and |.Y|. .X and .Y must be modulated to prevent a stable inverted body. 858 // side |.X| will increase to 1 and .Z fall to 0. As body inverts |.X| will fall
859 // and .Z will go // negative. Similar for tilt and |.Y|. .X and .Y must be
860 // modulated to prevent a stable inverted body.
760 861
761 // Error is 0 (no error) to +/- 2 (max error) 862 // Error is 0 (no error) to +/- 2 (max error)
762 if (verterr.Z < 0.0f) 863 if (verticalError.Z < 0.0f)
763 { 864 {
764 verterr.X = 2.0f - verterr.X; 865 verticalError.X = 2.0f - verticalError.X;
765 verterr.Y = 2.0f - verterr.Y; 866 verticalError.Y = 2.0f - verticalError.Y;
766 } 867 }
767 // scale it by VAservo 868 // scale it by VAservo (timestep and timescale)
768 verterr = verterr * VAservo; 869 verticalError = verticalError * VAservo;
769 870
770 // As the body rotates around the X axis, then verterr.Y increases; Rotated around Y then .X increases, so 871 // As the body rotates around the X axis, then verticalError.Y increases; Rotated around Y
771 // Change Body angular velocity X based on Y, and Y based on X. Z is not changed. 872 // then .X increases, so change Body angular velocity X based on Y, and Y based on X.
772 vertattr.X = verterr.Y; 873 // Z is not changed.
773 vertattr.Y = - verterr.X; 874 vertattr.X = verticalError.Y;
875 vertattr.Y = - verticalError.X;
774 vertattr.Z = 0f; 876 vertattr.Z = 0f;
775 877
776 // scaling appears better usingsquare-law 878 // scaling appears better usingsquare-law
879 Vector3 angularVelocity = Prim.ForceRotationalVelocity;
777 float bounce = 1.0f - (m_verticalAttractionEfficiency * m_verticalAttractionEfficiency); 880 float bounce = 1.0f - (m_verticalAttractionEfficiency * m_verticalAttractionEfficiency);
778 vertattr.X += bounce * angularVelocity.X; 881 vertattr.X += bounce * angularVelocity.X;
779 vertattr.Y += bounce * angularVelocity.Y; 882 vertattr.Y += bounce * angularVelocity.Y;
780 883
781 VDetailLog("{0},MoveAngular,verticalAttraction,verterr={1},bounce={2},vertattr={3}", 884 VDetailLog("{0},MoveAngular,verticalAttraction,VAservo={1},effic={2},verticalError={3},bounce={4},vertattr={5}",
782 Prim.LocalID, verterr, bounce, vertattr); 885 Prim.LocalID, VAservo, m_verticalAttractionEfficiency, verticalError, bounce, vertattr);
783 886
784 } // else vertical attractor is off 887 }
888 #endregion // Vertical attactor
785 889
786 m_lastVertAttractor = vertattr; 890 #region Deflection
891
892 if (m_angularDeflectionEfficiency != 0)
893 {
894 // Compute a scaled vector that points in the preferred axis (X direction)
895 Vector3 scaledDefaultDirection =
896 new Vector3((pTimestep * 10 * (m_angularDeflectionEfficiency / m_angularDeflectionTimescale)), 0, 0);
897 // Adding the current vehicle orientation and reference frame displaces the orientation to the frame.
898 // Rotate the scaled default axix relative to the actual vehicle direction giving where it should point.
899 Vector3 preferredAxisOfMotion = scaledDefaultDirection * Quaternion.Add(Prim.ForceOrientation, m_referenceFrame);
900
901 // Scale by efficiency and timescale
902 deflection = (preferredAxisOfMotion * (m_angularDeflectionEfficiency) / m_angularDeflectionTimescale) * pTimestep;
903
904 VDetailLog("{0},MoveAngular,Deflection,perfAxis={1},deflection={2}",
905 Prim.LocalID, preferredAxisOfMotion, deflection);
906 // This deflection computation is not correct.
907 deflection = Vector3.Zero;
908 }
787 909
788 // Bank section tba 910 #endregion
789 911
790 // Deflection section tba 912 #region Banking
913
914 if (m_bankingEfficiency != 0)
915 {
916 Vector3 dir = Vector3.One * Prim.ForceOrientation;
917 float mult = (m_bankingMix*m_bankingMix)*-1*(m_bankingMix < 0 ? -1 : 1);
918 //Changes which way it banks in and out of turns
919
920 //Use the square of the efficiency, as it looks much more how SL banking works
921 float effSquared = (m_bankingEfficiency*m_bankingEfficiency);
922 if (m_bankingEfficiency < 0)
923 effSquared *= -1; //Keep the negative!
924
925 float mix = Math.Abs(m_bankingMix);
926 if (m_angularMotorVelocity.X == 0)
927 {
928 /*if (!parent.Orientation.ApproxEquals(this.m_referenceFrame, 0.25f))
929 {
930 Vector3 axisAngle;
931 float angle;
932 parent.Orientation.GetAxisAngle(out axisAngle, out angle);
933 Vector3 rotatedVel = parent.Velocity * parent.Orientation;
934 if ((rotatedVel.X < 0 && axisAngle.Y > 0) || (rotatedVel.X > 0 && axisAngle.Y < 0))
935 m_angularMotorVelocity.X += (effSquared * (mult * mix)) * (1f) * 10;
936 else
937 m_angularMotorVelocity.X += (effSquared * (mult * mix)) * (-1f) * 10;
938 }*/
939 }
940 else
941 banking.Z += (effSquared*(mult*mix))*(m_angularMotorVelocity.X) * 4;
942 if (!Prim.IsColliding && Math.Abs(m_angularMotorVelocity.X) > mix)
943 //If they are colliding, we probably shouldn't shove the prim around... probably
944 {
945 float angVelZ = m_angularMotorVelocity.X*-1;
946 /*if(angVelZ > mix)
947 angVelZ = mix;
948 else if(angVelZ < -mix)
949 angVelZ = -mix;*/
950 //This controls how fast and how far the banking occurs
951 Vector3 bankingRot = new Vector3(angVelZ*(effSquared*mult), 0, 0);
952 if (bankingRot.X > 3)
953 bankingRot.X = 3;
954 else if (bankingRot.X < -3)
955 bankingRot.X = -3;
956 bankingRot *= Prim.ForceOrientation;
957 banking += bankingRot;
958 }
959 m_angularMotorVelocity.X *= m_bankingEfficiency == 1 ? 0.0f : 1 - m_bankingEfficiency;
960 VDetailLog("{0},MoveAngular,Banking,bEff={1},angMotVel={2},banking={3}",
961 Prim.LocalID, m_bankingEfficiency, m_angularMotorVelocity, banking);
962 }
963
964 #endregion
965
966 m_lastVertAttractor = vertattr;
791 967
792 // Sum velocities 968 // Sum velocities
793 m_lastAngularVelocity = m_angularMotorVelocity + vertattr; // + bank + deflection 969 m_lastAngularVelocity = m_angularMotorVelocity + vertattr + banking + deflection;
794 970
971 #region Linear Motor Offset
972
973 //Offset section
974 if (m_linearMotorOffset != Vector3.Zero)
975 {
976 //Offset of linear velocity doesn't change the linear velocity,
977 // but causes a torque to be applied, for example...
978 //
979 // IIIII >>> IIIII
980 // IIIII >>> IIIII
981 // IIIII >>> IIIII
982 // ^
983 // | Applying a force at the arrow will cause the object to move forward, but also rotate
984 //
985 //
986 // The torque created is the linear velocity crossed with the offset
987
988 // NOTE: this computation does should be in the linear section
989 // because there we know the impulse being applied.
990 Vector3 torqueFromOffset = Vector3.Zero;
991 // torqueFromOffset = Vector3.Cross(m_linearMotorOffset, appliedImpulse);
992 if (float.IsNaN(torqueFromOffset.X))
993 torqueFromOffset.X = 0;
994 if (float.IsNaN(torqueFromOffset.Y))
995 torqueFromOffset.Y = 0;
996 if (float.IsNaN(torqueFromOffset.Z))
997 torqueFromOffset.Z = 0;
998 torqueFromOffset *= m_vehicleMass;
999 Prim.ApplyTorqueImpulse(torqueFromOffset, true);
1000 VDetailLog("{0},BSDynamic.MoveAngular,motorOffset,applyTorqueImpulse={1}", Prim.LocalID, torqueFromOffset);
1001 }
1002
1003 #endregion
1004
795 if ((m_flags & (VehicleFlag.NO_DEFLECTION_UP)) != 0) 1005 if ((m_flags & (VehicleFlag.NO_DEFLECTION_UP)) != 0)
796 { 1006 {
797 m_lastAngularVelocity.X = 0; 1007 m_lastAngularVelocity.X = 0;
@@ -802,55 +1012,56 @@ namespace OpenSim.Region.Physics.BulletSPlugin
802 if (m_lastAngularVelocity.ApproxEquals(Vector3.Zero, 0.01f)) 1012 if (m_lastAngularVelocity.ApproxEquals(Vector3.Zero, 0.01f))
803 { 1013 {
804 m_lastAngularVelocity = Vector3.Zero; // Reduce small value to zero. 1014 m_lastAngularVelocity = Vector3.Zero; // Reduce small value to zero.
805 VDetailLog("{0},MoveAngular,zeroSmallValues,lastAngular={1}", Prim.LocalID, m_lastAngularVelocity); 1015 Prim.ZeroAngularMotion(true);
1016 VDetailLog("{0},MoveAngular,zeroAngularMotion,lastAngular={1}", Prim.LocalID, m_lastAngularVelocity);
1017 }
1018 else
1019 {
1020 // Apply to the body.
1021 // The above calculates the absolute angular velocity needed. Angular velocity is massless.
1022 // Since we are stuffing the angular velocity directly into the object, the computed
1023 // velocity needs to be scaled by the timestep.
1024 Vector3 applyAngularForce = ((m_lastAngularVelocity * pTimestep) - Prim.ForceRotationalVelocity);
1025 Prim.ForceRotationalVelocity = applyAngularForce;
1026
1027 // Decay the angular movement for next time
1028 Vector3 decayamount = (Vector3.One / m_angularFrictionTimescale) * pTimestep;
1029 m_lastAngularVelocity *= Vector3.One - decayamount;
1030
1031 VDetailLog("{0},MoveAngular,done,newRotVel={1},decay={2},lastAngular={3}",
1032 Prim.LocalID, applyAngularForce, decayamount, m_lastAngularVelocity);
806 } 1033 }
807
808 // apply friction
809 Vector3 decayamount = Vector3.One / (m_angularFrictionTimescale / pTimestep);
810 m_lastAngularVelocity -= m_lastAngularVelocity * decayamount;
811
812 // Apply to the body
813 Prim.ForceRotationalVelocity = m_lastAngularVelocity;
814
815 VDetailLog("{0},MoveAngular,done,decay={1},lastAngular={2}", Prim.LocalID, decayamount, m_lastAngularVelocity);
816 } //end MoveAngular 1034 } //end MoveAngular
817 1035
818 internal void LimitRotation(float timestep) 1036 internal void LimitRotation(float timestep)
819 { 1037 {
820 Quaternion rotq = Prim.ForceOrientation; 1038 Quaternion rotq = Prim.ForceOrientation;
821 Quaternion m_rot = rotq; 1039 Quaternion m_rot = rotq;
822 bool changed = false;
823 if (m_RollreferenceFrame != Quaternion.Identity) 1040 if (m_RollreferenceFrame != Quaternion.Identity)
824 { 1041 {
825 if (rotq.X >= m_RollreferenceFrame.X) 1042 if (rotq.X >= m_RollreferenceFrame.X)
826 { 1043 {
827 m_rot.X = rotq.X - (m_RollreferenceFrame.X / 2); 1044 m_rot.X = rotq.X - (m_RollreferenceFrame.X / 2);
828 changed = true;
829 } 1045 }
830 if (rotq.Y >= m_RollreferenceFrame.Y) 1046 if (rotq.Y >= m_RollreferenceFrame.Y)
831 { 1047 {
832 m_rot.Y = rotq.Y - (m_RollreferenceFrame.Y / 2); 1048 m_rot.Y = rotq.Y - (m_RollreferenceFrame.Y / 2);
833 changed = true;
834 } 1049 }
835 if (rotq.X <= -m_RollreferenceFrame.X) 1050 if (rotq.X <= -m_RollreferenceFrame.X)
836 { 1051 {
837 m_rot.X = rotq.X + (m_RollreferenceFrame.X / 2); 1052 m_rot.X = rotq.X + (m_RollreferenceFrame.X / 2);
838 changed = true;
839 } 1053 }
840 if (rotq.Y <= -m_RollreferenceFrame.Y) 1054 if (rotq.Y <= -m_RollreferenceFrame.Y)
841 { 1055 {
842 m_rot.Y = rotq.Y + (m_RollreferenceFrame.Y / 2); 1056 m_rot.Y = rotq.Y + (m_RollreferenceFrame.Y / 2);
843 changed = true;
844 } 1057 }
845 changed = true;
846 } 1058 }
847 if ((m_flags & VehicleFlag.LOCK_ROTATION) != 0) 1059 if ((m_flags & VehicleFlag.LOCK_ROTATION) != 0)
848 { 1060 {
849 m_rot.X = 0; 1061 m_rot.X = 0;
850 m_rot.Y = 0; 1062 m_rot.Y = 0;
851 changed = true;
852 } 1063 }
853 if (changed) 1064 if (rotq != m_rot)
854 { 1065 {
855 Prim.ForceOrientation = m_rot; 1066 Prim.ForceOrientation = m_rot;
856 VDetailLog("{0},LimitRotation,done,orig={1},new={2}", Prim.LocalID, rotq, m_rot); 1067 VDetailLog("{0},LimitRotation,done,orig={1},new={2}", Prim.LocalID, rotq, m_rot);