RigsofRods
Soft-body Physics Simulation
TurboJet.cpp
Go to the documentation of this file.
1 /*
2  This source file is part of Rigs of Rods
3  Copyright 2005-2012 Pierre-Michel Ricordel
4  Copyright 2007-2012 Thomas Fischer
5  Copyright 2017-2020 Petr Ohlidal
6 
7  For more information, see http://www.rigsofrods.org/
8 
9  Rigs of Rods is free software: you can redistribute it and/or modify
10  it under the terms of the GNU General Public License version 3, as
11  published by the Free Software Foundation.
12 
13  Rigs of Rods is distributed in the hope that it will be useful,
14  but WITHOUT ANY WARRANTY; without even the implied warranty of
15  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16  GNU General Public License for more details.
17 
18  You should have received a copy of the GNU General Public License
19  along with Rigs of Rods. If not, see <http://www.gnu.org/licenses/>.
20 */
21 
22 #include "TurboJet.h"
23 
24 #include <Ogre.h>
25 
26 #include "Application.h"
27 #include "Actor.h"
28 #include "SimData.h"
29 #include "GfxActor.h"
30 #include "GfxScene.h"
31 #include "SoundScriptManager.h"
32 
33 using namespace Ogre;
34 using namespace RoR;
35 
36 Turbojet::Turbojet(ActorPtr actor, NodeNum_t tnodefront, NodeNum_t tnodeback, NodeNum_t tnoderef, RigDef::Turbojet & def)
37 {
38  m_actor = actor;
39 #ifdef USE_OPENAL
40  switch (actor->ar_num_aeroengines)
41  {
42  case 0: m_sound_mod = SS_MOD_AEROENGINE1; m_sound_src = SS_TRIG_AEROENGINE1; m_sound_thr = SS_MOD_THROTTLE1; m_sound_ab = SS_TRIG_AFTERBURNER1; break;
43  case 1: m_sound_mod = SS_MOD_AEROENGINE2; m_sound_src = SS_TRIG_AEROENGINE2; m_sound_thr = SS_MOD_THROTTLE2; m_sound_ab = SS_TRIG_AFTERBURNER2; break;
44  case 2: m_sound_mod = SS_MOD_AEROENGINE3; m_sound_src = SS_TRIG_AEROENGINE3; m_sound_thr = SS_MOD_THROTTLE3; m_sound_ab = SS_TRIG_AFTERBURNER3; break;
45  case 3: m_sound_mod = SS_MOD_AEROENGINE4; m_sound_src = SS_TRIG_AEROENGINE4; m_sound_thr = SS_MOD_THROTTLE4; m_sound_ab = SS_TRIG_AFTERBURNER4; break;
46  case 4: m_sound_mod = SS_MOD_AEROENGINE5; m_sound_src = SS_TRIG_AEROENGINE5; m_sound_thr = SS_MOD_THROTTLE5; m_sound_ab = SS_TRIG_AFTERBURNER5; break;
47  case 5: m_sound_mod = SS_MOD_AEROENGINE6; m_sound_src = SS_TRIG_AEROENGINE6; m_sound_thr = SS_MOD_THROTTLE6; m_sound_ab = SS_TRIG_AFTERBURNER6; break;
48  case 6: m_sound_mod = SS_MOD_AEROENGINE7; m_sound_src = SS_TRIG_AEROENGINE7; m_sound_thr = SS_MOD_THROTTLE7; m_sound_ab = SS_TRIG_AFTERBURNER7; break;
49  case 7: m_sound_mod = SS_MOD_AEROENGINE8; m_sound_src = SS_TRIG_AEROENGINE8; m_sound_thr = SS_MOD_THROTTLE8; m_sound_ab = SS_TRIG_AFTERBURNER8; break;
50  default: m_sound_mod = SS_MOD_NONE; m_sound_src = SS_TRIG_NONE; m_sound_thr = SS_MOD_NONE; m_sound_ab = SS_TRIG_NONE;
51  }
52 #endif
53  m_node_back = tnodeback;
54  m_node_front = tnodefront;
55  m_node_ref = tnoderef;
56  tjet_afterburnable = (def.wet_thrust > 0.f);
57  m_reversable = def.is_reversable != 0;
58  m_max_dry_thrust = def.dry_thrust;
59  m_afterburn_thrust = def.wet_thrust;
60  m_afterburner_active = false;
61  m_timer = 0;
62  m_warmup_time = 15.0;
63  m_last_flip = 0;
64  m_radius = def.back_diameter / 2.f;
65  m_area = 2 * 3.14159 * m_radius * 0.6 * m_radius * 0.6;
66  m_exhaust_velocity = 0;
67  m_axis = m_actor->ar_nodes[m_node_front].RelPosition - m_actor->ar_nodes[m_node_back].RelPosition;
68  m_reflen = m_axis.length();
69  m_axis = m_axis / m_reflen;
70  reset();
71 }
72 
73 void TurbojetVisual::SetupVisuals(RigDef::Turbojet & def, int num, std::string const& propname, Ogre::Entity* nozzle, Ogre::Entity* afterburner_flame)
74 {
75  m_radius = def.back_diameter / 2.0;
76  m_number = num;
77 
78  m_nozzle_entity = nozzle;
79  m_nozzle_scenenode = App::GetGfxScene()->GetSceneManager()->getRootSceneNode()->createChildSceneNode();
80  m_nozzle_scenenode->attachObject(m_nozzle_entity);
81  m_nozzle_scenenode->setScale(def.nozzle_length, def.back_diameter, def.back_diameter);
82 
83  if (afterburner_flame != nullptr)
84  {
85  m_flame_entity = afterburner_flame;
86  m_flame_scenenode = App::GetGfxScene()->GetSceneManager()->getRootSceneNode()->createChildSceneNode();
87  m_flame_scenenode->attachObject(m_flame_entity);
88  m_flame_scenenode->setScale(1.0, def.back_diameter, def.back_diameter);
89  m_flame_scenenode->setVisible(false);
90  }
91 
92  //smoke visual
93  m_smoke_scenenode = App::GetGfxScene()->GetSceneManager()->getRootSceneNode()->createChildSceneNode();
94  m_smoke_particle = App::GetGfxScene()->GetSceneManager()->createParticleSystem("SmokeParticle-"+propname, "tracks/TurbopropSmoke");
95  if (m_smoke_particle)
96  {
97  m_smoke_particle->setVisibilityFlags(DEPTHMAP_DISABLED); // disable particles in depthmap
98  m_smoke_scenenode->attachObject(m_smoke_particle);
99  m_smoke_particle->setCastShadows(false);
100  }
101 
102 }
103 
104 void TurbojetVisual::SetNodes(NodeNum_t front, NodeNum_t back, NodeNum_t ref)
105 {
106  ROR_ASSERT(front != NODENUM_INVALID);
107  ROR_ASSERT(back != NODENUM_INVALID);
108 
109  m_node_front = front;
110  m_node_back = back;
111  m_node_ref = ref;
112 }
113 
114 Turbojet::~Turbojet()
115 {
116  //A fast work around
117  //
118  SOUND_MODULATE(m_actor, m_sound_thr, 0);
119  SOUND_MODULATE(m_actor, m_sound_mod, 0);
120  SOUND_STOP(m_actor, m_sound_ab);
121  SOUND_STOP(m_actor, m_sound_src);
122 }
123 
124 TurbojetVisual::~TurbojetVisual()
125 {
126  if (m_flame_entity != nullptr)
127  {
128  m_flame_entity->setVisible(false);
129  }
130 
131  if (m_nozzle_entity != nullptr)
132  {
133  m_nozzle_entity->setVisible(false);
134  }
135 
136  if (m_smoke_particle != nullptr)
137  {
138  m_smoke_particle->removeAllEmitters();
139  }
140 }
141 
142 void Turbojet::updateVisuals(RoR::GfxActor* gfx_actor)
143 {
144  if (this->tjet_visual.IsVisible())
145  this->tjet_visual.UpdateVisuals(gfx_actor);
146 }
147 
148 void Turbojet::setVisible(bool visible)
149 {
150  this->tjet_visual.SetVisible(visible);
151 }
152 
153 void TurbojetVisual::UpdateVisuals(RoR::GfxActor* gfx_actor)
154 {
155  RoR::NodeSB* node_buf = gfx_actor->GetSimNodeBuffer();
156  RoR::AeroEngineSB& ae_buf
157  = gfx_actor->GetSimDataBuffer().simbuf_aeroengines.at(m_number);
158 
159  //nozzle
160  m_nozzle_scenenode->setPosition(node_buf[m_node_back].AbsPosition);
161  //build a local system
162  Vector3 laxis = node_buf[m_node_front].AbsPosition - node_buf[m_node_back].AbsPosition;
163  laxis.normalise();
164  Vector3 paxis = Plane(laxis, 0).projectVector(node_buf[m_node_ref].AbsPosition - node_buf[m_node_back].AbsPosition);
165  paxis.normalise();
166  Vector3 taxis = laxis.crossProduct(paxis);
167  Quaternion dir = Quaternion(laxis, paxis, taxis);
168  m_nozzle_scenenode->setOrientation(dir);
169  //afterburner
170  if (ae_buf.simbuf_tj_afterburn)
171  {
172  m_flame_scenenode->setVisible(true);
173  float flamelength = (ae_buf.simbuf_tj_ab_thrust / 15.0) * (ae_buf.simbuf_ae_rpmpc / 100.0);
174  flamelength = flamelength * (1.0 + (((Real)rand() / (Real)RAND_MAX) - 0.5) / 10.0);
175  m_flame_scenenode->setScale(flamelength, m_radius * 2.0, m_radius * 2.0);
176  m_flame_scenenode->setPosition(node_buf[m_node_back].AbsPosition + dir * Vector3(-0.2, 0.0, 0.0));
177  m_flame_scenenode->setOrientation(dir);
178  }
179  else
180  m_flame_scenenode->setVisible(false);
181 
182  //smoke
183  if (m_smoke_particle &&
185  {
186  m_smoke_scenenode->setPosition(node_buf[m_node_back].AbsPosition);
187  ParticleEmitter* emit = m_smoke_particle->getEmitter(0);
188  emit->setDirection(-laxis);
189  emit->setParticleVelocity(ae_buf.simbuf_tj_exhaust_velo);
190  if (!ae_buf.simbuf_ae_failed)
191  {
192  if (ae_buf.simbuf_ae_ignition)
193  {
194  emit->setEnabled(true);
195  emit->setColour(ColourValue(0.0, 0.0, 0.0, 0.02 + ae_buf.simbuf_ae_throttle * 0.03));
196  emit->setTimeToLive((0.02 + ae_buf.simbuf_ae_throttle * 0.03) / 0.1);
197  }
198  else
199  {
200  emit->setEnabled(false);
201  }
202  }
203  else
204  {
205  emit->setDirection(Vector3(0, 1, 0));
206  emit->setParticleVelocity(7.0);
207  emit->setEnabled(true);
208  emit->setColour(ColourValue(0.0, 0.0, 0.0, 0.1));
209  emit->setTimeToLive(0.1 / 0.1);
210  }
211  }
212 }
213 
214 void TurbojetVisual::SetVisible(bool visible)
215 {
216  m_visible = visible;
217  m_smoke_particle->setVisible(visible);
218  m_nozzle_scenenode->setVisible(visible);
219  if (!visible)
220  {
221  // only hide, regular update will restore visibility if needed.
222  m_flame_scenenode->setVisible(false);
223  }
224 }
225 
226 void Turbojet::updateForces(float dt, int doUpdate)
227 {
228  if (doUpdate)
229  {
230  SOUND_MODULATE(m_actor, m_sound_mod, m_rpm_percent);
231  }
232  m_timer += dt;
233  m_axis = m_actor->ar_nodes[m_node_front].RelPosition - m_actor->ar_nodes[m_node_back].RelPosition;
234  float axlen = m_axis.length();
235  m_axis = m_axis / axlen; //normalize
236  if (fabs(m_reflen - axlen) > 0.1)
237  {
238  m_rpm_percent = 0;
239  m_is_failed = true;
240  }; //check for broken
241 
242  float warmupfactor = 1.0;
243  if (m_warmup)
244  {
245  warmupfactor = (m_timer - m_warmup_start) / m_warmup_time;
246  if (warmupfactor >= 1.0)
247  m_warmup = false;
248  }
249 
250  //turbine RPM
251  //braking (compression)
252  if (m_rpm_percent < 0)
253  m_rpm_percent = 0;
254  float torque = -m_rpm_percent / 100.0;
255  //powering with limiter
256  if (m_rpm_percent < 100.0 && !m_is_failed && m_ignition)
257  torque += ((0.2 + m_throtle * 0.8) * warmupfactor);
258  //integration
259  m_rpm_percent += (double)dt * torque * 30.0;
260 
261  float enginethrust = 0;
262  if (!m_is_failed && m_ignition)
263  {
264  enginethrust = m_max_dry_thrust * m_rpm_percent / 100.0;
265  m_afterburner_active = (tjet_afterburnable && m_throtle > 0.95 && m_rpm_percent > 80);
266  if (m_afterburner_active)
267  enginethrust += (m_afterburn_thrust - m_max_dry_thrust);
268  }
269  else
270  m_afterburner_active = false;
271 
272  if (m_afterburner_active)
273  SOUND_START(m_actor, m_sound_ab);
274  else
275  SOUND_STOP(m_actor, m_sound_ab);
276 
277  if (m_reverse)
278  m_actor->ar_nodes[m_node_back].Forces -= (enginethrust * 1000.0) * m_axis;
279  else
280  m_actor->ar_nodes[m_node_back].Forces += (enginethrust * 1000.0) * m_axis;
281 
282  m_exhaust_velocity = enginethrust * 5.6 / m_area;
283 }
284 
285 void Turbojet::setThrottle(float val)
286 {
287  if (val > 1.0)
288  val = 1.0;
289 
290  if (val < 0.0)
291  val = 0.0;
292 
293  m_throtle = val;
294  SOUND_MODULATE(m_actor, m_sound_thr, val);
295 }
296 
297 float Turbojet::getThrottle()
298 {
299  return m_throtle;
300 }
301 
302 void Turbojet::setRPM(float _rpm)
303 {
304  m_rpm_percent = _rpm;
305 }
306 
307 void Turbojet::reset()
308 {
309  m_rpm_percent = 0;
310  m_throtle = 0;
311  m_propwash = 0;
312  m_is_failed = false;
313  m_ignition = false;
314  m_reverse = false;
315 }
316 
317 void Turbojet::toggleReverse()
318 {
319  if (!m_reversable)
320  return;
321  m_throtle = 0;
322  m_reverse = !m_reverse;
323 }
324 
325 void Turbojet::setReverse(bool val)
326 {
327  m_reverse = val;
328 }
329 
330 void Turbojet::flipStart()
331 {
332  if (m_timer - m_last_flip < 0.3)
333  return;
334  m_ignition = !m_ignition;
335  if (m_ignition && !m_is_failed)
336  {
337  m_warmup = true;
338  m_warmup_start = m_timer;
339  SOUND_START(m_actor, m_sound_src);
340  }
341  else
342  {
343  SOUND_STOP(m_actor, m_sound_src);
344  }
345 
346  m_last_flip = m_timer;
347 }
ROR_ASSERT
#define ROR_ASSERT(_EXPR)
Definition: Application.h:40
RoR::SS_MOD_THROTTLE7
@ SS_MOD_THROTTLE7
Definition: SoundScriptManager.h:145
RoR::SS_TRIG_AEROENGINE8
@ SS_TRIG_AEROENGINE8
Definition: SoundScriptManager.h:96
RoR::SS_MOD_THROTTLE6
@ SS_MOD_THROTTLE6
Definition: SoundScriptManager.h:144
RoR::SS_MOD_AEROENGINE1
@ SS_MOD_AEROENGINE1
Definition: SoundScriptManager.h:127
RoR::SS_TRIG_AFTERBURNER6
@ SS_TRIG_AFTERBURNER6
Definition: SoundScriptManager.h:90
RoR::SS_MOD_AEROENGINE5
@ SS_MOD_AEROENGINE5
Definition: SoundScriptManager.h:147
RoR::NodeSB
Definition: SimBuffers.h:67
RoR::SS_TRIG_AEROENGINE2
@ SS_TRIG_AEROENGINE2
Definition: SoundScriptManager.h:56
RoR::GfxActor::GetSimNodeBuffer
NodeSB * GetSimNodeBuffer()
Definition: GfxActor.h:120
RoR::SS_TRIG_AEROENGINE6
@ SS_TRIG_AEROENGINE6
Definition: SoundScriptManager.h:94
RoR::NODENUM_INVALID
static const NodeNum_t NODENUM_INVALID
Definition: ForwardDeclarations.h:53
RoR::SS_TRIG_AFTERBURNER5
@ SS_TRIG_AFTERBURNER5
Definition: SoundScriptManager.h:89
RoR::ActorSB::simbuf_smoke_enabled
bool simbuf_smoke_enabled
Definition: SimBuffers.h:165
RoR::SS_TRIG_AFTERBURNER2
@ SS_TRIG_AFTERBURNER2
Definition: SoundScriptManager.h:86
RoR::AeroEngineSB
Definition: SimBuffers.h:90
RoR::AeroEngineSB::simbuf_tj_exhaust_velo
float simbuf_tj_exhaust_velo
Turbojet afterburner.
Definition: SimBuffers.h:99
RoR::SS_MOD_AEROENGINE4
@ SS_MOD_AEROENGINE4
Definition: SoundScriptManager.h:130
RoR::SS_TRIG_AEROENGINE3
@ SS_TRIG_AEROENGINE3
Definition: SoundScriptManager.h:57
RoR::SS_MOD_AEROENGINE8
@ SS_MOD_AEROENGINE8
Definition: SoundScriptManager.h:150
RoR::ActorSB::simbuf_aeroengines
std::vector< AeroEngineSB > simbuf_aeroengines
Definition: SimBuffers.h:138
RoR::SS_MOD_AEROENGINE2
@ SS_MOD_AEROENGINE2
Definition: SoundScriptManager.h:128
RefCountingObjectPtr< Actor >
Actor.h
RoR::GfxScene::GetSceneManager
Ogre::SceneManager * GetSceneManager()
Definition: GfxScene.h:64
RoR::SS_TRIG_AFTERBURNER4
@ SS_TRIG_AFTERBURNER4
Definition: SoundScriptManager.h:88
TurboJet.h
RigDef::Turbojet::back_diameter
float back_diameter
Definition: RigDef_File.h:1397
RoR::NodeNum_t
uint16_t NodeNum_t
Node position within Actor::ar_nodes; use RoR::NODENUM_INVALID as empty value.
Definition: ForwardDeclarations.h:52
RoR::Actor::ar_num_aeroengines
int ar_num_aeroengines
Definition: Actor.h:324
SimData.h
Core data structures for simulation; Everything affected by by either physics, network or user intera...
RoR::SS_MOD_THROTTLE1
@ SS_MOD_THROTTLE1
Definition: SoundScriptManager.h:139
RoR::SS_TRIG_AEROENGINE1
@ SS_TRIG_AEROENGINE1
Definition: SoundScriptManager.h:55
RoR::AeroEngineSB::simbuf_ae_rpmpc
float simbuf_ae_rpmpc
Definition: SimBuffers.h:94
GfxScene.h
SOUND_START
#define SOUND_START(_ACTOR_, _TRIG_)
Definition: SoundScriptManager.h:35
Application.h
Central state/object manager and communications hub.
RigDef::Turbojet::wet_thrust
float wet_thrust
Definition: RigDef_File.h:1395
SoundScriptManager.h
RoR::SS_MOD_THROTTLE3
@ SS_MOD_THROTTLE3
Definition: SoundScriptManager.h:141
RoR::SS_MOD_NONE
@ SS_MOD_NONE
Definition: SoundScriptManager.h:124
RoR::SS_TRIG_AEROENGINE4
@ SS_TRIG_AEROENGINE4
Definition: SoundScriptManager.h:58
RoR::AeroEngineSB::simbuf_ae_throttle
float simbuf_ae_throttle
Definition: SimBuffers.h:95
SOUND_STOP
#define SOUND_STOP(_ACTOR_, _TRIG_)
Definition: SoundScriptManager.h:36
RoR::SS_MOD_AEROENGINE7
@ SS_MOD_AEROENGINE7
Definition: SoundScriptManager.h:149
RoR::NodeSB::AbsPosition
Ogre::Vector3 AbsPosition
Definition: SimBuffers.h:69
RoR::AeroEngineSB::simbuf_tj_ab_thrust
float simbuf_tj_ab_thrust
Definition: SimBuffers.h:98
SOUND_MODULATE
#define SOUND_MODULATE(_ACTOR_, _MOD_, _VALUE_)
Definition: SoundScriptManager.h:40
RoR::SS_TRIG_AEROENGINE5
@ SS_TRIG_AEROENGINE5
Definition: SoundScriptManager.h:93
RoR::SS_MOD_THROTTLE5
@ SS_MOD_THROTTLE5
Definition: SoundScriptManager.h:143
RoR::SS_MOD_THROTTLE4
@ SS_MOD_THROTTLE4
Definition: SoundScriptManager.h:142
RigDef::Turbojet::dry_thrust
float dry_thrust
Definition: RigDef_File.h:1394
RoR::SS_TRIG_AEROENGINE7
@ SS_TRIG_AEROENGINE7
Definition: SoundScriptManager.h:95
RoR::GfxActor
Definition: GfxActor.h:52
RigDef::Turbojet::nozzle_length
float nozzle_length
Definition: RigDef_File.h:1398
Ogre
Definition: ExtinguishableFireAffector.cpp:35
GfxActor.h
Manager for all visuals belonging to a single actor.
RoR::AeroEngineSB::simbuf_ae_failed
bool simbuf_ae_failed
Definition: SimBuffers.h:101
RigDef::Turbojet::is_reversable
int is_reversable
Definition: RigDef_File.h:1393
RoR::SS_TRIG_AFTERBURNER7
@ SS_TRIG_AFTERBURNER7
Definition: SoundScriptManager.h:91
RoR::DEPTHMAP_DISABLED
@ DEPTHMAP_DISABLED
Definition: Application.h:285
RoR::SS_MOD_AEROENGINE6
@ SS_MOD_AEROENGINE6
Definition: SoundScriptManager.h:148
RoR::SS_TRIG_AFTERBURNER3
@ SS_TRIG_AFTERBURNER3
Definition: SoundScriptManager.h:87
RigDef::Turbojet
Definition: RigDef_File.h:1388
RoR::AeroEngineSB::simbuf_ae_ignition
bool simbuf_ae_ignition
Turbojet.
Definition: SimBuffers.h:100
RoR::SS_TRIG_NONE
@ SS_TRIG_NONE
Definition: SoundScriptManager.h:53
RoR::SS_MOD_THROTTLE2
@ SS_MOD_THROTTLE2
Definition: SoundScriptManager.h:140
RoR::SS_MOD_AEROENGINE3
@ SS_MOD_AEROENGINE3
Definition: SoundScriptManager.h:129
RoR::SS_TRIG_AFTERBURNER8
@ SS_TRIG_AFTERBURNER8
Definition: SoundScriptManager.h:92
RoR::AeroEngineSB::simbuf_tj_afterburn
bool simbuf_tj_afterburn
Definition: SimBuffers.h:102
RoR::GfxActor::GetSimDataBuffer
ActorSB & GetSimDataBuffer()
Definition: GfxActor.h:119
RoR
Definition: AppContext.h:36
RoR::App::GetGfxScene
GfxScene * GetGfxScene()
Definition: Application.cpp:276
RoR::SS_MOD_THROTTLE8
@ SS_MOD_THROTTLE8
Definition: SoundScriptManager.h:146
RoR::SS_TRIG_AFTERBURNER1
@ SS_TRIG_AFTERBURNER1
Definition: SoundScriptManager.h:85