1 //
2 // Copyright (c) 2008-2017 the Urho3D project.
3 //
4 // Permission is hereby granted, free of charge, to any person obtaining a copy
5 // of this software and associated documentation files (the "Software"), to deal
6 // in the Software without restriction, including without limitation the rights
7 // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8 // copies of the Software, and to permit persons to whom the Software is
9 // furnished to do so, subject to the following conditions:
10 //
11 // The above copyright notice and this permission notice shall be included in
12 // all copies or substantial portions of the Software.
13 //
14 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15 // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17 // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18 // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19 // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
20 // THE SOFTWARE.
21 //
22 
23 #include "../Core/Context.h"
24 #include "../Physics/PhysicsUtils.h"
25 #include "../Physics/RigidBody.h"
26 #include "../Physics/PhysicsWorld.h"
27 #include "../Scene/Scene.h"
28 #include "../IO/Log.h"
29 #include "../Physics/RaycastVehicle.h"
30 
31 #include <Bullet/BulletDynamics/Vehicle/btRaycastVehicle.h>
32 #include <Bullet/BulletDynamics/Dynamics/btDiscreteDynamicsWorld.h>
33 
34 namespace Urho3D
35 {
36 
37 struct RaycastVehicleData
38 {
RaycastVehicleDataUrho3D::RaycastVehicleData39     RaycastVehicleData()
40     {
41         vehicleRayCaster_ = 0;
42         vehicle_ = 0;
43         added_ = false;
44     }
45 
~RaycastVehicleDataUrho3D::RaycastVehicleData46     ~RaycastVehicleData()
47     {
48         if (vehicleRayCaster_)
49         {
50             delete vehicleRayCaster_;
51         }
52         vehicleRayCaster_ = 0;
53         if (vehicle_)
54         {
55             if (physWorld_ && added_)
56             {
57                 btDynamicsWorld* pbtDynWorld = physWorld_->GetWorld();
58                 if (pbtDynWorld)
59                     pbtDynWorld->removeAction(vehicle_);
60                 added_ = false;
61             }
62             delete vehicle_;
63         }
64         vehicle_ = 0;
65     }
66 
GetUrho3D::RaycastVehicleData67     btRaycastVehicle* Get()
68     {
69         return vehicle_;
70     }
71 
InitUrho3D::RaycastVehicleData72     void Init(Scene* scene, RigidBody* body, bool enabled)
73     {
74         int rightIndex = 0;
75         int upIndex = 1;
76         int forwardIndex = 2;
77         PhysicsWorld* pPhysWorld = scene->GetComponent<PhysicsWorld>();
78         btDynamicsWorld* pbtDynWorld = pPhysWorld->GetWorld();
79         if (!pbtDynWorld)
80             return;
81 
82         // Delete old vehicle & action first
83         if (vehicleRayCaster_)
84             delete vehicleRayCaster_;
85         if (vehicle_)
86         {
87             if (added_)
88                 pbtDynWorld->removeAction(vehicle_);
89             delete vehicle_;
90         }
91 
92         vehicleRayCaster_ = new btDefaultVehicleRaycaster(pbtDynWorld);
93         btRigidBody* bthullBody = body->GetBody();
94         vehicle_ = new btRaycastVehicle(tuning_, bthullBody, vehicleRayCaster_);
95         if (enabled)
96         {
97             pbtDynWorld->addAction(vehicle_);
98             added_ = true;
99         }
100 
101         vehicle_->setCoordinateSystem(rightIndex, upIndex, forwardIndex);
102         physWorld_ = pPhysWorld;
103     }
104 
SetEnabledUrho3D::RaycastVehicleData105     void SetEnabled(bool enabled)
106     {
107         if (!physWorld_ || !vehicle_)
108             return;
109         btDynamicsWorld* pbtDynWorld = physWorld_->GetWorld();
110         if (!pbtDynWorld)
111             return;
112 
113         if (enabled && !added_)
114         {
115             pbtDynWorld->addAction(vehicle_);
116             added_ = true;
117         }
118         else if (!enabled && added_)
119         {
120             pbtDynWorld->removeAction(vehicle_);
121             added_ = false;
122         }
123     }
124 
125     WeakPtr<PhysicsWorld> physWorld_;
126     btVehicleRaycaster* vehicleRayCaster_;
127     btRaycastVehicle* vehicle_;
128     btRaycastVehicle::btVehicleTuning tuning_;
129     bool added_;
130 };
131 
RaycastVehicle(Context * context)132 RaycastVehicle::RaycastVehicle(Context* context) :
133     LogicComponent(context)
134 {
135     // fixed update() for inputs and post update() to sync wheels for rendering
136     SetUpdateEventMask(USE_FIXEDUPDATE | USE_FIXEDPOSTUPDATE | USE_POSTUPDATE);
137     vehicleData_ = new RaycastVehicleData();
138     wheelNodes_.Clear();
139     activate_ = false;
140     inAirRPM_ = 0.0f;
141     maxSideSlipSpeed_ = 4.0f;
142 }
143 
~RaycastVehicle()144 RaycastVehicle::~RaycastVehicle()
145 {
146     delete vehicleData_;
147     wheelNodes_.Clear();
148 }
149 
150 const char* wheelElementNames[] =
151 {
152     "Number of wheels",
153     "   Wheel node id",
154     "   Wheel direction",
155     "   Wheel axle",
156     "   Wheel rest length",
157     "   Wheel radius",
158     "   Wheel is front wheel",
159     "   Steering",
160     "   Connection point vector",
161     "   Original rotation",
162     "   Cumulative skid info",
163     "   Side skip speed",
164     "   Grounded",
165     "   Contact position",
166     "   Contact normal",
167     "   Suspension stiffness",
168     "   Damping relaxation",
169     "   Damping compression",
170     "   Friction slip",
171     "   Roll influence",
172     "   Engine force",
173     "   Brake",
174     0
175 };
176 
RegisterObject(Context * context)177 void RaycastVehicle::RegisterObject(Context* context)
178 {
179     context->RegisterFactory<RaycastVehicle>();
180     URHO3D_MIXED_ACCESSOR_VARIANT_VECTOR_STRUCTURE_ATTRIBUTE("Wheel data", GetWheelDataAttr, SetWheelDataAttr,
181             VariantVector, Variant::emptyVariantVector,
182             wheelElementNames, AM_DEFAULT);
183     URHO3D_ATTRIBUTE("Maximum side slip threshold", float, maxSideSlipSpeed_, 4.0f, AM_DEFAULT);
184     URHO3D_ATTRIBUTE("RPM for wheel motors in air (0=calculate)", float, inAirRPM_, 0.0f, AM_DEFAULT);
185 }
186 
OnSetEnabled()187 void RaycastVehicle::OnSetEnabled()
188 {
189     if (vehicleData_)
190         vehicleData_->SetEnabled(IsEnabledEffective());
191 }
192 
ApplyAttributes()193 void RaycastVehicle::ApplyAttributes()
194 {
195     int index = 0;
196     hullBody_ = node_->GetOrCreateComponent<RigidBody>();
197     Scene* scene = GetScene();
198     vehicleData_->Init(scene, hullBody_, IsEnabledEffective());
199     VariantVector& value = loadedWheelData_;
200     int numObjects = value[index++].GetInt();
201     int wheelIndex = 0;
202     origRotation_.Clear();
203     skidInfoCumulative_.Clear();
204     wheelSideSlipSpeed_.Clear();
205 
206     for (int i = 0; i < numObjects; i++)
207     {
208         int node_id = value[index++].GetInt();
209         Vector3 direction = value[index++].GetVector3();
210         Vector3 axle = value[index++].GetVector3();
211         float restLength = value[index++].GetFloat();
212         float radius = value[index++].GetFloat();
213         bool isFrontWheel = value[index++].GetBool();
214         float steering = value[index++].GetFloat();
215         Vector3 connectionPoint = value[index++].GetVector3();
216         Quaternion origRotation = value[index++].GetQuaternion();
217         float skidInfoC = value[index++].GetFloat();
218         float sideSlipSpeed = value[index++].GetFloat();
219 
220         bool isContact = value[index++].GetBool();
221         Vector3 contactPosition = value[index++].GetVector3();
222         Vector3 contactNormal = value[index++].GetVector3();
223         float suspensionStiffness = value[index++].GetFloat();
224         float dampingRelaxation = value[index++].GetFloat();
225         float dampingCompression = value[index++].GetFloat();
226         float frictionSlip = value[index++].GetFloat();
227         float rollInfluence = value[index++].GetFloat();
228         float engineForce = value[index++].GetFloat();
229         float brake = value[index++].GetFloat();
230         float skidInfo = value[index++].GetFloat();
231         Node* wheelNode = GetScene()->GetNode(node_id);
232         if (!wheelNode)
233         {
234             URHO3D_LOGERROR("RaycastVehicle: Incorrect node id = " + String(node_id) + " index: " + String(index));
235             continue;
236         }
237         btRaycastVehicle* vehicle = vehicleData_->Get();
238         int id = GetNumWheels();
239         btVector3 connectionPointCS0(connectionPoint.x_, connectionPoint.y_, connectionPoint.z_);
240         btVector3 wheelDirectionCS0(direction.x_, direction.y_, direction.z_);
241         btVector3 wheelAxleCS(axle.x_, axle.y_, axle.z_);
242         btWheelInfo& wheel = vehicle->addWheel(connectionPointCS0,
243                                 wheelDirectionCS0,
244                                 wheelAxleCS,
245                                 restLength,
246                                 radius,
247                                 vehicleData_->tuning_,
248                                 isFrontWheel);
249         wheelNodes_.Push(wheelNode);
250         origRotation_.Push(origRotation);
251         skidInfoCumulative_.Push(skidInfoC);
252         wheelSideSlipSpeed_.Push(sideSlipSpeed);
253         SetSteeringValue(wheelIndex, steering);
254         wheel.m_raycastInfo.m_isInContact = isContact;
255         wheel.m_raycastInfo.m_contactNormalWS = btVector3(contactNormal.x_, contactNormal.y_, contactNormal.z_);
256         wheel.m_raycastInfo.m_contactPointWS = btVector3(contactPosition.x_, contactPosition.y_, contactPosition.z_);
257         wheel.m_suspensionStiffness = suspensionStiffness;
258         wheel.m_wheelsDampingRelaxation = dampingRelaxation;
259         wheel.m_wheelsDampingCompression = dampingCompression;
260         wheel.m_frictionSlip = frictionSlip;
261         wheel.m_rollInfluence = rollInfluence;
262         wheel.m_engineForce = engineForce;
263         wheel.m_brake = brake;
264         wheel.m_skidInfo = skidInfo;
265         wheelIndex++;
266     }
267     URHO3D_LOGDEBUG("maxSideSlipSpeed_ value: " + String(maxSideSlipSpeed_));
268     URHO3D_LOGDEBUG("loaded items: " + String(index));
269     URHO3D_LOGDEBUG("loaded wheels: " + String(GetNumWheels()));
270 }
271 
Init()272 void RaycastVehicle::Init()
273 {
274     hullBody_ = node_->GetOrCreateComponent<RigidBody>();
275     Scene* scene = GetScene();
276     vehicleData_->Init(scene, hullBody_, IsEnabledEffective());
277 }
278 
FixedUpdate(float timeStep)279 void RaycastVehicle::FixedUpdate(float timeStep)
280 {
281     btRaycastVehicle* vehicle = vehicleData_->Get();
282     for (int i = 0; i < GetNumWheels(); i++)
283     {
284         btWheelInfo whInfo = vehicle->getWheelInfo(i);
285         if (whInfo.m_engineForce != 0.0f || whInfo.m_steering != 0.0f)
286         {
287             hullBody_->Activate();
288             break;
289         }
290     }
291 }
292 
PostUpdate(float timeStep)293 void RaycastVehicle::PostUpdate(float timeStep)
294 {
295     btRaycastVehicle* vehicle = vehicleData_->Get();
296     for (int i = 0; i < GetNumWheels(); i++)
297     {
298         vehicle->updateWheelTransform(i, true);
299         btTransform transform = vehicle->getWheelTransformWS(i);
300         Vector3 origin = ToVector3(transform.getOrigin());
301         Quaternion qRot = ToQuaternion(transform.getRotation());
302         Node* pWheel = wheelNodes_[i];
303         pWheel->SetWorldPosition(origin);
304         pWheel->SetWorldRotation(qRot * origRotation_[i]);
305     }
306 }
307 
FixedPostUpdate(float timeStep)308 void RaycastVehicle::FixedPostUpdate(float timeStep)
309 {
310     btRaycastVehicle* vehicle = vehicleData_->Get();
311     Vector3 velocity = hullBody_->GetLinearVelocity();
312     for (int i = 0; i < GetNumWheels(); i++)
313     {
314         btWheelInfo& whInfo = vehicle->getWheelInfo(i);
315         if (!WheelIsGrounded(i) && GetEngineForce(i) != 0.0f)
316         {
317             float delta;
318             if (inAirRPM_ != 0.0f)
319             {
320                 delta = inAirRPM_ * timeStep / 60.0f;
321             }
322             else
323             {
324                 delta = 8.0f * GetEngineForce(i) * timeStep / (hullBody_->GetMass() * GetWheelRadius(i));
325             }
326             if (Abs(whInfo.m_deltaRotation) < Abs(delta))
327             {
328                 whInfo.m_rotation += delta - whInfo.m_deltaRotation;
329                 whInfo.m_deltaRotation = delta;
330             }
331             if (skidInfoCumulative_[i] > 0.05f)
332             {
333                 skidInfoCumulative_[i] -= 0.002;
334             }
335         }
336         else
337         {
338             skidInfoCumulative_[i] = GetWheelSkidInfo(i);
339         }
340         wheelSideSlipSpeed_[i] = Abs(ToVector3(whInfo.m_raycastInfo.m_wheelAxleWS).DotProduct(velocity));
341         if (wheelSideSlipSpeed_[i] > maxSideSlipSpeed_)
342         {
343             skidInfoCumulative_[i] = Clamp(skidInfoCumulative_[i], 0.0f, 0.89f);
344         }
345     }
346 }
347 
SetMaxSideSlipSpeed(float speed)348 void RaycastVehicle::SetMaxSideSlipSpeed(float speed)
349 {
350     maxSideSlipSpeed_ = speed;
351 }
352 
GetMaxSideSlipSpeed() const353 float RaycastVehicle::GetMaxSideSlipSpeed() const
354 {
355     return maxSideSlipSpeed_;
356 }
357 
SetWheelSkidInfoCumulative(int wheel,float skid)358 void RaycastVehicle::SetWheelSkidInfoCumulative(int wheel, float skid)
359 {
360     skidInfoCumulative_[wheel] = skid;
361 }
362 
GetWheelSkidInfoCumulative(int wheel) const363 float RaycastVehicle::GetWheelSkidInfoCumulative(int wheel) const
364 {
365     return skidInfoCumulative_[wheel];
366 }
367 
AddWheel(Node * wheelNode,Vector3 wheelDirection,Vector3 wheelAxle,float restLength,float wheelRadius,bool frontWheel)368 void RaycastVehicle::AddWheel(Node* wheelNode,
369                                 Vector3 wheelDirection, Vector3 wheelAxle,
370                                 float restLength, float wheelRadius,
371                                 bool frontWheel)
372 {
373     btRaycastVehicle* vehicle = vehicleData_->Get();
374     int id = GetNumWheels();
375     Vector3 connectionPoint = wheelNode->GetWorldPosition() - node_->GetWorldPosition();
376     btVector3 connectionPointCS0(connectionPoint.x_, connectionPoint.y_, connectionPoint.z_);
377     btVector3 wheelDirectionCS0(wheelDirection.x_, wheelDirection.y_, wheelDirection.z_);
378     btVector3 wheelAxleCS(wheelAxle.x_, wheelAxle.y_, wheelAxle.z_);
379     btWheelInfo& wheel = vehicle->addWheel(connectionPointCS0,
380                             wheelDirectionCS0,
381                             wheelAxleCS,
382                             restLength,
383                             wheelRadius,
384                             vehicleData_->tuning_,
385                             frontWheel);
386 
387     wheelNodes_.Push(wheelNode);
388     origRotation_.Push(wheelNode->GetWorldRotation());
389     skidInfoCumulative_.Push(1.0f);
390     wheelSideSlipSpeed_.Push(0.0f);
391     wheel.m_raycastInfo.m_isInContact = false;
392 }
393 
ResetSuspension()394 void RaycastVehicle::ResetSuspension()
395 {
396     btRaycastVehicle* vehicle = vehicleData_->Get();
397     vehicle->resetSuspension();
398 }
399 
UpdateWheelTransform(int wheel,bool interpolated)400 void RaycastVehicle::UpdateWheelTransform(int wheel, bool interpolated)
401 {
402     btRaycastVehicle* vehicle = vehicleData_->Get();
403     vehicle->updateWheelTransform(wheel, interpolated);
404 }
405 
GetWheelPosition(int wheel)406 Vector3 RaycastVehicle::GetWheelPosition(int wheel)
407 {
408     btRaycastVehicle* vehicle = vehicleData_->Get();
409     btTransform transform = vehicle->getWheelTransformWS(wheel);
410     Vector3 origin = ToVector3(transform.getOrigin());
411     return origin;
412 }
413 
GetWheelRotation(int wheel)414 Quaternion RaycastVehicle::GetWheelRotation(int wheel)
415 {
416     btRaycastVehicle* vehicle = vehicleData_->Get();
417     btTransform transform = vehicle->getWheelTransformWS(wheel);
418     Quaternion rotation = ToQuaternion(transform.getRotation());
419     return rotation;
420 }
421 
GetWheelConnectionPoint(int wheel) const422 Vector3 RaycastVehicle::GetWheelConnectionPoint(int wheel) const
423 {
424     btRaycastVehicle* vehicle = vehicleData_->Get();
425     btWheelInfo whInfo = vehicle->getWheelInfo(wheel);
426     return ToVector3(whInfo.m_chassisConnectionPointCS);
427 }
428 
SetSteeringValue(int wheel,float steeringValue)429 void RaycastVehicle::SetSteeringValue(int wheel, float steeringValue)
430 {
431     btRaycastVehicle* vehicle = vehicleData_->Get();
432     vehicle->setSteeringValue(steeringValue, wheel);
433 }
434 
GetSteeringValue(int wheel) const435 float RaycastVehicle::GetSteeringValue(int wheel) const
436 {
437     btRaycastVehicle* vehicle = vehicleData_->Get();
438     btWheelInfo whInfo = vehicle->getWheelInfo(wheel);
439     return whInfo.m_steering;
440 }
441 
SetWheelSuspensionStiffness(int wheel,float stiffness)442 void RaycastVehicle::SetWheelSuspensionStiffness(int wheel, float stiffness)
443 {
444     btRaycastVehicle* vehicle = vehicleData_->Get();
445     btWheelInfo& whInfo = vehicle->getWheelInfo(wheel);
446     whInfo.m_suspensionStiffness = stiffness;
447 }
448 
GetWheelSuspensionStiffness(int wheel) const449 float RaycastVehicle::GetWheelSuspensionStiffness(int wheel) const
450 {
451     btRaycastVehicle* vehicle = vehicleData_->Get();
452     btWheelInfo whInfo = vehicle->getWheelInfo(wheel);
453     return whInfo.m_suspensionStiffness;
454 }
455 
SetWheelDampingRelaxation(int wheel,float damping)456 void RaycastVehicle::SetWheelDampingRelaxation(int wheel, float damping)
457 {
458     btRaycastVehicle* vehicle = vehicleData_->Get();
459     btWheelInfo& whInfo = vehicle->getWheelInfo(wheel);
460     whInfo.m_wheelsDampingRelaxation = damping;
461 }
462 
GetWheelDampingRelaxation(int wheel) const463 float RaycastVehicle::GetWheelDampingRelaxation(int wheel) const
464 {
465     btRaycastVehicle* vehicle = vehicleData_->Get();
466     btWheelInfo whInfo = vehicle->getWheelInfo(wheel);
467     return whInfo.m_wheelsDampingRelaxation;
468 }
469 
SetWheelDampingCompression(int wheel,float compression)470 void RaycastVehicle::SetWheelDampingCompression(int wheel, float compression)
471 {
472     btRaycastVehicle* vehicle = vehicleData_->Get();
473     btWheelInfo& whInfo = vehicle->getWheelInfo(wheel);
474     whInfo.m_wheelsDampingCompression = compression;
475 }
476 
GetWheelDampingCompression(int wheel) const477 float RaycastVehicle::GetWheelDampingCompression(int wheel) const
478 {
479     btRaycastVehicle* vehicle = vehicleData_->Get();
480     btWheelInfo whInfo = vehicle->getWheelInfo(wheel);
481     return whInfo.m_wheelsDampingCompression;
482 }
483 
SetWheelFrictionSlip(int wheel,float slip)484 void RaycastVehicle::SetWheelFrictionSlip(int wheel, float slip)
485 {
486     btRaycastVehicle* vehicle = vehicleData_->Get();
487     btWheelInfo& whInfo = vehicle->getWheelInfo(wheel);
488     whInfo.m_frictionSlip = slip;
489 }
490 
GetWheelFrictionSlip(int wheel) const491 float RaycastVehicle::GetWheelFrictionSlip(int wheel) const
492 {
493     btRaycastVehicle* vehicle = vehicleData_->Get();
494     btWheelInfo whInfo = vehicle->getWheelInfo(wheel);
495     return whInfo.m_frictionSlip;
496 }
497 
SetWheelRollInfluence(int wheel,float rollInfluence)498 void RaycastVehicle::SetWheelRollInfluence(int wheel, float rollInfluence)
499 {
500     btRaycastVehicle* vehicle = vehicleData_->Get();
501     btWheelInfo& whInfo = vehicle->getWheelInfo(wheel);
502     whInfo.m_rollInfluence = rollInfluence;
503 }
504 
GetContactPosition(int wheel) const505 Vector3 RaycastVehicle::GetContactPosition(int wheel) const
506 {
507     btRaycastVehicle* vehicle = vehicleData_->Get();
508     btWheelInfo& whInfo = vehicle->getWheelInfo(wheel);
509     return ToVector3(whInfo.m_raycastInfo.m_contactPointWS);
510 }
511 
GetContactNormal(int wheel) const512 Vector3 RaycastVehicle::GetContactNormal(int wheel) const
513 {
514     btRaycastVehicle* vehicle = vehicleData_->Get();
515     btWheelInfo& whInfo = vehicle->getWheelInfo(wheel);
516     return ToVector3(whInfo.m_raycastInfo.m_contactNormalWS);
517 }
518 
GetWheelSideSlipSpeed(int wheel) const519 float RaycastVehicle::GetWheelSideSlipSpeed(int wheel) const
520 {
521     return wheelSideSlipSpeed_[wheel];
522 }
523 
GetWheelRollInfluence(int wheel) const524 float RaycastVehicle::GetWheelRollInfluence(int wheel) const
525 {
526     btRaycastVehicle* vehicle = vehicleData_->Get();
527     btWheelInfo whInfo = vehicle->getWheelInfo(wheel);
528     return whInfo.m_rollInfluence;
529 }
530 
SetWheelRadius(int wheel,float wheelRadius)531 void RaycastVehicle::SetWheelRadius(int wheel, float wheelRadius)
532 {
533     btRaycastVehicle* vehicle = vehicleData_->Get();
534     btWheelInfo& whInfo = vehicle->getWheelInfo(wheel);
535     whInfo.m_wheelsRadius = wheelRadius;
536 }
537 
GetWheelRadius(int wheel) const538 float RaycastVehicle::GetWheelRadius(int wheel) const
539 {
540     btRaycastVehicle* vehicle = vehicleData_->Get();
541     btWheelInfo& whInfo = vehicle->getWheelInfo(wheel);
542     return whInfo.m_wheelsRadius;
543 }
544 
SetEngineForce(int wheel,float force)545 void RaycastVehicle::SetEngineForce(int wheel, float force)
546 {
547     btRaycastVehicle* vehicle = vehicleData_->Get();
548     vehicle->applyEngineForce(force, wheel);
549 }
550 
GetEngineForce(int wheel) const551 float RaycastVehicle::GetEngineForce(int wheel) const
552 {
553     btRaycastVehicle* vehicle = vehicleData_->Get();
554     btWheelInfo whInfo = vehicle->getWheelInfo(wheel);
555     return whInfo.m_engineForce;
556 }
557 
SetBrake(int wheel,float force)558 void RaycastVehicle::SetBrake(int wheel, float force)
559 {
560     btRaycastVehicle* vehicle = vehicleData_->Get();
561     vehicle->setBrake(force, wheel);
562 }
563 
GetBrake(int wheel) const564 float RaycastVehicle::GetBrake(int wheel) const
565 {
566     btRaycastVehicle* vehicle = vehicleData_->Get();
567     btWheelInfo whInfo = vehicle->getWheelInfo(wheel);
568     return whInfo.m_brake;
569 }
570 
GetNumWheels() const571 int RaycastVehicle::GetNumWheels() const
572 {
573     btRaycastVehicle* vehicle = vehicleData_->Get();
574     return vehicle->getNumWheels();
575 }
576 
GetWheelNode(int wheel) const577 Node* RaycastVehicle::GetWheelNode(int wheel) const
578 {
579     return wheelNodes_[wheel];
580 }
581 
SetMaxSuspensionTravel(int wheel,float maxSuspensionTravel)582 void RaycastVehicle::SetMaxSuspensionTravel(int wheel, float maxSuspensionTravel)
583 {
584     btRaycastVehicle* vehicle = vehicleData_->Get();
585     btWheelInfo& whInfo = vehicle->getWheelInfo(wheel);
586     whInfo.m_maxSuspensionTravelCm = maxSuspensionTravel;
587 }
588 
GetMaxSuspensionTravel(int wheel)589 float RaycastVehicle::GetMaxSuspensionTravel(int wheel)
590 {
591     btRaycastVehicle* vehicle = vehicleData_->Get();
592     btWheelInfo whInfo = vehicle->getWheelInfo(wheel);
593     return whInfo.m_maxSuspensionTravelCm;
594 }
595 
SetWheelDirection(int wheel,Vector3 direction)596 void RaycastVehicle::SetWheelDirection(int wheel, Vector3 direction)
597 {
598     btVector3 dir(direction.x_, direction.y_, direction.z_);
599     btRaycastVehicle* vehicle = vehicleData_->Get();
600     btWheelInfo& whInfo = vehicle->getWheelInfo(wheel);
601     whInfo.m_wheelDirectionCS = dir;
602 }
603 
GetWheelDirection(int wheel) const604 Vector3 RaycastVehicle::GetWheelDirection(int wheel) const
605 {
606     btRaycastVehicle* vehicle = vehicleData_->Get();
607     btWheelInfo& whInfo = vehicle->getWheelInfo(wheel);
608     return ToVector3(whInfo.m_wheelDirectionCS);
609 }
610 
SetWheelAxle(int wheel,Vector3 axle)611 void RaycastVehicle::SetWheelAxle(int wheel, Vector3 axle)
612 {
613     btVector3 ax(axle.x_, axle.y_, axle.z_);
614     btRaycastVehicle* vehicle = vehicleData_->Get();
615     btWheelInfo& whInfo = vehicle->getWheelInfo(wheel);
616     whInfo.m_wheelAxleCS = ax;
617 }
618 
GetWheelAxle(int wheel) const619 Vector3 RaycastVehicle::GetWheelAxle(int wheel) const
620 {
621     btRaycastVehicle* vehicle = vehicleData_->Get();
622     btWheelInfo& whInfo = vehicle->getWheelInfo(wheel);
623     return ToVector3(whInfo.m_wheelAxleCS);
624 }
625 
SetWheelRestLength(int wheel,float length)626 void RaycastVehicle::SetWheelRestLength(int wheel, float length)
627 {
628     btRaycastVehicle* vehicle = vehicleData_->Get();
629     btWheelInfo& whInfo = vehicle->getWheelInfo(wheel);
630     whInfo.m_suspensionRestLength1 = length;
631 }
632 
GetWheelRestLength(int wheel) const633 float RaycastVehicle::GetWheelRestLength(int wheel) const
634 {
635     btRaycastVehicle* vehicle = vehicleData_->Get();
636     btWheelInfo& whInfo = vehicle->getWheelInfo(wheel);
637     return whInfo.m_suspensionRestLength1;
638 }
639 
SetWheelSkidInfo(int wheel,float factor)640 void RaycastVehicle::SetWheelSkidInfo(int wheel, float factor)
641 {
642     btRaycastVehicle* vehicle = vehicleData_->Get();
643     btWheelInfo& whInfo = vehicle->getWheelInfo(wheel);
644     whInfo.m_skidInfo = factor;
645 }
646 
GetWheelSkidInfo(int wheel) const647 float RaycastVehicle::GetWheelSkidInfo(int wheel) const
648 {
649     btRaycastVehicle* vehicle = vehicleData_->Get();
650     btWheelInfo& whInfo = vehicle->getWheelInfo(wheel);
651     return whInfo.m_skidInfo;
652 }
653 
IsFrontWheel(int wheel) const654 bool RaycastVehicle::IsFrontWheel(int wheel) const
655 {
656     btRaycastVehicle* vehicle = vehicleData_->Get();
657     btWheelInfo& whInfo = vehicle->getWheelInfo(wheel);
658     return whInfo.m_bIsFrontWheel;
659 }
660 
WheelIsGrounded(int wheel) const661 bool RaycastVehicle::WheelIsGrounded(int wheel) const
662 {
663     btRaycastVehicle* vehicle = vehicleData_->Get();
664     btWheelInfo whInfo = vehicle->getWheelInfo(wheel);
665     return whInfo.m_raycastInfo.m_isInContact;
666 }
667 
SetInAirRPM(float rpm)668 void RaycastVehicle::SetInAirRPM(float rpm)
669 {
670     inAirRPM_ = rpm;
671 }
672 
GetInAirRPM() const673 float RaycastVehicle::GetInAirRPM() const
674 {
675     return inAirRPM_;
676 }
677 
ResetWheels()678 void RaycastVehicle::ResetWheels()
679 {
680     ResetSuspension();
681     for (int i = 0; i < GetNumWheels(); i++)
682     {
683         UpdateWheelTransform(i, true);
684         Vector3 origin = GetWheelPosition(i);
685         Node* wheelNode = GetWheelNode(i);
686         wheelNode->SetWorldPosition(origin);
687     }
688 }
689 
GetWheelDataAttr() const690 VariantVector RaycastVehicle::GetWheelDataAttr() const
691 {
692     VariantVector ret;
693     ret.Reserve(GetNumWheels() * 22 + 1);
694     ret.Push(GetNumWheels());
695     for (int i = 0; i < GetNumWheels(); i++)
696     {
697         Node* wNode = GetWheelNode(i);
698         int node_id = wNode->GetID();
699         URHO3D_LOGDEBUG("RaycastVehicle: Saving node id = " + String(node_id));
700         ret.Push(node_id);
701         ret.Push(GetWheelDirection(i));
702         ret.Push(GetWheelAxle(i));
703         ret.Push(GetWheelRestLength(i));
704         ret.Push(GetWheelRadius(i));
705         ret.Push(IsFrontWheel(i));
706         ret.Push(GetSteeringValue(i));
707         ret.Push(GetWheelConnectionPoint(i));
708         ret.Push(origRotation_[i]);
709         ret.Push(GetWheelSkidInfoCumulative(i));
710         ret.Push(GetWheelSideSlipSpeed(i));
711         ret.Push(WheelIsGrounded(i));
712         ret.Push(GetContactPosition(i));
713         ret.Push(GetContactNormal(i));       // 14
714         ret.Push(GetWheelSuspensionStiffness(i));
715         ret.Push(GetWheelDampingRelaxation(i));
716         ret.Push(GetWheelDampingCompression(i));
717         ret.Push(GetWheelFrictionSlip(i));
718         ret.Push(GetWheelRollInfluence(i));
719         ret.Push(GetEngineForce(i));
720         ret.Push(GetBrake(i));
721         ret.Push(GetWheelSkidInfo(i));
722     }
723     URHO3D_LOGDEBUG("RaycastVehicle: saved items: " + String(ret.Size()));
724     URHO3D_LOGDEBUG("maxSideSlipSpeed_ value save: " + String(maxSideSlipSpeed_));
725     return ret;
726 }
727 
SetWheelDataAttr(const VariantVector & value)728 void RaycastVehicle::SetWheelDataAttr(const VariantVector& value)
729 {
730     if (!vehicleData_)
731     {
732         URHO3D_LOGERROR("RaycastVehicle: vehicleData doesn't exist");
733         return;
734     }
735     if (value.Size() < 2)
736     {
737         URHO3D_LOGERROR("RaycastVehicle: Incorrect vehicleData");
738         return;
739     }
740 
741     loadedWheelData_ = value;
742 }
743 
744 } // namespace Urho3D
745