RigsofRods
Soft-body Physics Simulation
All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Modules Pages
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  {
187  m_smoke_scenenode->setPosition(node_buf[m_node_back].AbsPosition);
188  ParticleEmitter* emit = m_smoke_particle->getEmitter(0);
189  emit->setDirection(-laxis);
190  emit->setParticleVelocity(ae_buf.simbuf_tj_exhaust_velo);
191  if (!ae_buf.simbuf_ae_failed)
192  {
193  if (ae_buf.simbuf_ae_ignition)
194  {
195  emit->setEnabled(true);
196  emit->setColour(ColourValue(0.0, 0.0, 0.0, 0.02 + ae_buf.simbuf_ae_throttle * 0.03));
197  emit->setTimeToLive((0.02 + ae_buf.simbuf_ae_throttle * 0.03) / 0.1);
198  }
199  else
200  {
201  emit->setEnabled(false);
202  }
203  }
204  else
205  {
206  emit->setDirection(Vector3(0, 1, 0));
207  emit->setParticleVelocity(7.0);
208  emit->setEnabled(true);
209  emit->setColour(ColourValue(0.0, 0.0, 0.0, 0.1));
210  emit->setTimeToLive(0.1 / 0.1);
211  }
212  }
213 }
214 
215 void TurbojetVisual::SetVisible(bool visible)
216 {
217  m_visible = visible;
218  m_smoke_particle->setVisible(visible);
219  m_nozzle_scenenode->setVisible(visible);
220  if (!visible)
221  {
222  // only hide, regular update will restore visibility if needed.
223  m_flame_scenenode->setVisible(false);
224  }
225 }
226 
227 void Turbojet::updateForces(float dt, int doUpdate)
228 {
229  if (doUpdate)
230  {
231  SOUND_MODULATE(m_actor, m_sound_mod, m_rpm_percent);
232  }
233  m_timer += dt;
234  m_axis = m_actor->ar_nodes[m_node_front].RelPosition - m_actor->ar_nodes[m_node_back].RelPosition;
235  float axlen = m_axis.length();
236  m_axis = m_axis / axlen; //normalize
237  if (fabs(m_reflen - axlen) > 0.1)
238  {
239  m_rpm_percent = 0;
240  m_is_failed = true;
241  }; //check for broken
242 
243  float warmupfactor = 1.0;
244  if (m_warmup)
245  {
246  warmupfactor = (m_timer - m_warmup_start) / m_warmup_time;
247  if (warmupfactor >= 1.0)
248  m_warmup = false;
249  }
250 
251  //turbine RPM
252  //braking (compression)
253  if (m_rpm_percent < 0)
254  m_rpm_percent = 0;
255  float torque = -m_rpm_percent / 100.0;
256  //powering with limiter
257  if (m_rpm_percent < 100.0 && !m_is_failed && m_ignition)
258  torque += ((0.2 + m_throtle * 0.8) * warmupfactor);
259  //integration
260  m_rpm_percent += (double)dt * torque * 30.0;
261 
262  float enginethrust = 0;
263  if (!m_is_failed && m_ignition)
264  {
265  enginethrust = m_max_dry_thrust * m_rpm_percent / 100.0;
266  m_afterburner_active = (tjet_afterburnable && m_throtle > 0.95 && m_rpm_percent > 80);
267  if (m_afterburner_active)
268  enginethrust += (m_afterburn_thrust - m_max_dry_thrust);
269  }
270  else
271  m_afterburner_active = false;
272 
273  if (m_afterburner_active)
274  SOUND_START(m_actor, m_sound_ab);
275  else
276  SOUND_STOP(m_actor, m_sound_ab);
277 
278  if (m_reverse)
279  m_actor->ar_nodes[m_node_back].Forces -= (enginethrust * 1000.0) * m_axis;
280  else
281  m_actor->ar_nodes[m_node_back].Forces += (enginethrust * 1000.0) * m_axis;
282 
283  m_exhaust_velocity = enginethrust * 5.6 / m_area;
284 }
285 
286 void Turbojet::setThrottle(float val)
287 {
288  if (val > 1.0)
289  val = 1.0;
290 
291  if (val < 0.0)
292  val = 0.0;
293 
294  m_throtle = val;
295  SOUND_MODULATE(m_actor, m_sound_thr, val);
296 }
297 
298 float Turbojet::getThrottle()
299 {
300  return m_throtle;
301 }
302 
303 void Turbojet::setRPM(float _rpm)
304 {
305  m_rpm_percent = _rpm;
306 }
307 
308 void Turbojet::reset()
309 {
310  m_rpm_percent = 0;
311  m_throtle = 0;
312  m_propwash = 0;
313  m_is_failed = false;
314  m_ignition = false;
315  m_reverse = false;
316 }
317 
318 void Turbojet::toggleReverse()
319 {
320  if (!m_reversable)
321  return;
322  m_throtle = 0;
323  m_reverse = !m_reverse;
324 }
325 
326 void Turbojet::setReverse(bool val)
327 {
328  m_reverse = val;
329 }
330 
331 void Turbojet::flipStart()
332 {
333  if (m_timer - m_last_flip < 0.3)
334  return;
335  m_ignition = !m_ignition;
336  if (m_ignition && !m_is_failed)
337  {
338  m_warmup = true;
339  m_warmup_start = m_timer;
340  SOUND_START(m_actor, m_sound_src);
341  }
342  else
343  {
344  SOUND_STOP(m_actor, m_sound_src);
345  }
346 
347  m_last_flip = m_timer;
348 }
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:129
RoR::SS_TRIG_AEROENGINE6
@ SS_TRIG_AEROENGINE6
Definition: SoundScriptManager.h:94
RoR::NODENUM_INVALID
static const NodeNum_t NODENUM_INVALID
Definition: ForwardDeclarations.h:55
RoR::SS_TRIG_AFTERBURNER5
@ SS_TRIG_AFTERBURNER5
Definition: SoundScriptManager.h:89
RoR::ActorSB::simbuf_smoke_enabled
bool simbuf_smoke_enabled
Definition: SimBuffers.h:166
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:69
RoR::SS_TRIG_AFTERBURNER4
@ SS_TRIG_AFTERBURNER4
Definition: SoundScriptManager.h:88
TurboJet.h
RigDef::Turbojet::back_diameter
float back_diameter
Definition: RigDef_File.h:1410
RoR::NodeNum_t
uint16_t NodeNum_t
Node position within Actor::ar_nodes; use RoR::NODENUM_INVALID as empty value.
Definition: ForwardDeclarations.h:54
RoR::Actor::ar_num_aeroengines
int ar_num_aeroengines
Definition: Actor.h:337
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:1408
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:1407
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:1411
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:1406
RoR::SS_TRIG_AFTERBURNER7
@ SS_TRIG_AFTERBURNER7
Definition: SoundScriptManager.h:91
RoR::DEPTHMAP_DISABLED
@ DEPTHMAP_DISABLED
Definition: Application.h:302
RoR::SS_MOD_AEROENGINE6
@ SS_MOD_AEROENGINE6
Definition: SoundScriptManager.h:148
RoR::GfxScene::AdjustParticleSystemTimeFactor
void AdjustParticleSystemTimeFactor(Ogre::ParticleSystem *psys)
Definition: GfxScene.cpp:428
RoR::SS_TRIG_AFTERBURNER3
@ SS_TRIG_AFTERBURNER3
Definition: SoundScriptManager.h:87
RigDef::Turbojet
Definition: RigDef_File.h:1401
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:128
RoR
Definition: AppContext.h:36
RoR::App::GetGfxScene
GfxScene * GetGfxScene()
Definition: Application.cpp:280
RoR::SS_MOD_THROTTLE8
@ SS_MOD_THROTTLE8
Definition: SoundScriptManager.h:146
RoR::SS_TRIG_AFTERBURNER1
@ SS_TRIG_AFTERBURNER1
Definition: SoundScriptManager.h:85