RigsofRods
Soft-body Physics Simulation
Replay.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 
6  For more information, see http://www.rigsofrods.org/
7 
8  Rigs of Rods is free software: you can redistribute it and/or modify
9  it under the terms of the GNU General Public License version 3, as
10  published by the Free Software Foundation.
11 
12  Rigs of Rods is distributed in the hope that it will be useful,
13  but WITHOUT ANY WARRANTY; without even the implied warranty of
14  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15  GNU General Public License for more details.
16 
17  You should have received a copy of the GNU General Public License
18  along with Rigs of Rods. If not, see <http://www.gnu.org/licenses/>.
19 */
20 
21 #include "Replay.h"
22 
23 #include "Application.h"
24 #include "Actor.h"
25 #include "ActorManager.h"
26 #include "GameContext.h"
27 #include "GUIManager.h"
28 #include "InputEngine.h"
29 #include "Language.h"
30 #include "Utils.h"
31 
32 using namespace Ogre;
33 using namespace RoR;
34 
35 Replay::Replay(ActorPtr actor, int _numFrames)
36 {
37  m_actor = actor;
38  numFrames = _numFrames;
39 
40  curFrameTime = 0;
41 
42  replayTimer = new Timer();
43 
44  // DO NOT get memory here, get memory when we use it first time!
45  nodes = 0;
46  beams = 0;
47  times = 0;
48 
49  outOfMemory = false;
50 
51  const int numNodes = actor->ar_num_nodes;
52  const int numBeams = actor->ar_num_beams;
53  unsigned long bsize = (numNodes * numFrames * sizeof(node_simple_t) + numBeams * numFrames * sizeof(beam_simple_t) + numFrames * sizeof(unsigned long)) / 1024.0f;
54  LOG("replay buffer size: " + TOSTRING(bsize) + " kB");
55 
56  writeIndex = 0;
57  firstRun = 1;
58 
59  int steps = App::sim_replay_stepping->getInt();
60 
61  if (steps <= 0)
62  this->ar_replay_precision = 0.0f;
63  else
64  this->ar_replay_precision = 1.0f / ((float)steps);
65 
66  // windowing
67  int width = 300;
68  int height = 60;
69  int x = (MyGUI::RenderManager::getInstance().getViewSize().width - width) / 2;
70  int y = 0;
71 }
72 
73 Replay::~Replay()
74 {
75  if (nodes)
76  {
77  free(nodes);
78  nodes = 0;
79  free(beams);
80  beams = 0;
81  free(times);
82  times = 0;
83  }
84  delete replayTimer;
85 }
86 
87 void* Replay::getWriteBuffer(int type)
88 {
89  if (outOfMemory)
90  return 0;
91  if (!nodes)
92  {
93  // get memory
94  nodes = (node_simple_t*)calloc(m_actor->ar_num_nodes * numFrames, sizeof(node_simple_t));
95  if (!nodes)
96  {
97  outOfMemory = true;
98  return 0;
99  }
100  beams = (beam_simple_t*)calloc(m_actor->ar_num_beams * numFrames, sizeof(beam_simple_t));
101  if (!beams)
102  {
103  free(nodes);
104  nodes = 0;
105  outOfMemory = true;
106  return 0;
107  }
108  times = (unsigned long*)calloc(numFrames, sizeof(unsigned long));
109  if (!times)
110  {
111  free(nodes);
112  nodes = 0;
113  free(beams);
114  beams = 0;
115  outOfMemory = true;
116  return 0;
117  }
118  }
119  void* ptr = 0;
120  times[writeIndex] = replayTimer->getMicroseconds();
121  if (type == 0)
122  {
123  // nodes
124  ptr = (void *)(nodes + (writeIndex * m_actor->ar_num_nodes));
125  }
126  else if (type == 1)
127  {
128  // beams
129  ptr = (void *)(beams + (writeIndex * m_actor->ar_num_beams));
130  }
131  return ptr;
132 }
133 
134 void Replay::writeDone()
135 {
136  if (outOfMemory)
137  return;
138  writeIndex++;
139  if (writeIndex == numFrames)
140  {
141  firstRun = 0;
142  writeIndex = 0;
143  }
144 }
145 
146 //we take negative offsets only
147 void* Replay::getReadBuffer(int offset, int type, unsigned long& time)
148 {
149  if (offset >= 0)
150  offset = -1;
151  if (offset <= -numFrames)
152  offset = -numFrames + 1;
153 
154  int delta = writeIndex + offset;
155  if (delta < 0)
156  if (firstRun && type == 0)
157  return (void *)(nodes);
158  else if (firstRun && type == 1)
159  return (void *)(beams);
160  else
161  delta += numFrames;
162 
163  // set the time
164  time = times[delta];
165  curFrameTime = time;
166 
167  if (outOfMemory)
168  return 0;
169 
170  // return buffer pointer
171  if (type == 0)
172  return (void *)(nodes + delta * m_actor->ar_num_nodes);
173  else if (type == 1)
174  return (void *)(beams + delta * m_actor->ar_num_beams);
175  return 0;
176 }
177 
178 unsigned long Replay::getLastReadTime()
179 {
180  return curFrameTime;
181 }
182 
183 void Replay::onPhysicsStep()
184 {
185  m_replay_timer += PHYSICS_DT;
186  if (m_replay_timer >= ar_replay_precision)
187  {
188  // store nodes
189  node_simple_t* nbuff = (node_simple_t *)this->getWriteBuffer(0);
190  if (nbuff)
191  {
192  for (int i = 0; i < m_actor->ar_num_nodes; i++)
193  {
194  nbuff[i].position = m_actor->ar_nodes[i].AbsPosition;
195  nbuff[i].velocity = m_actor->ar_nodes[i].Velocity;
196  }
197  }
198 
199  // store beams
200  beam_simple_t* bbuff = (beam_simple_t *)this->getWriteBuffer(1);
201  if (bbuff)
202  {
203  for (int i = 0; i < m_actor->ar_num_beams; i++)
204  {
205  bbuff[i].broken = m_actor->ar_beams[i].bm_broken;
206  bbuff[i].disabled = m_actor->ar_beams[i].bm_disabled;
207  }
208  }
209 
210  this->writeDone();
211  m_replay_timer = 0.0f;
212  }
213 }
214 
215 void Replay::replayStepActor()
216 {
217  if (ar_replay_pos != m_replay_pos_prev)
218  {
219  unsigned long time = 0;
220 
221  node_simple_t* nbuff = (node_simple_t *)this->getReadBuffer(ar_replay_pos, 0, time);
222  if (nbuff)
223  {
224  for (int i = 0; i < m_actor->ar_num_nodes; i++)
225  {
226  m_actor->ar_nodes[i].AbsPosition = nbuff[i].position;
227  m_actor->ar_nodes[i].RelPosition = nbuff[i].position - m_actor->ar_origin;
228 
229  m_actor->ar_nodes[i].Velocity = nbuff[i].velocity;
230  m_actor->ar_nodes[i].Forces = Vector3::ZERO;
231  }
232 
233  m_actor->updateSlideNodePositions();
234  m_actor->UpdateBoundingBoxes();
235  m_actor->calculateAveragePosition();
236  }
237 
238  beam_simple_t* bbuff = (beam_simple_t *)this->getReadBuffer(ar_replay_pos, 1, time);
239  if (bbuff)
240  {
241  for (int i = 0; i < m_actor->ar_num_beams; i++)
242  {
243  m_actor->ar_beams[i].bm_broken = bbuff[i].broken;
244  m_actor->ar_beams[i].bm_disabled = bbuff[i].disabled;
245  }
246  }
247  m_replay_pos_prev = ar_replay_pos;
248  }
249 }
250 
251 void Replay::UpdateInputEvents()
252 {
253  if (App::GetInputEngine()->getEventBoolValueBounce(EV_COMMON_TOGGLE_REPLAY_MODE))
254  {
255  if (m_actor->ar_state == ActorState::LOCAL_REPLAY)
256  m_actor->ar_state = ActorState::LOCAL_SIMULATED;
257  else
258  m_actor->ar_state = ActorState::LOCAL_REPLAY;
259  }
260 
261  if (m_actor->ar_state == ActorState::LOCAL_REPLAY)
262  {
263  if (App::GetInputEngine()->getEventBoolValueBounce(EV_COMMON_REPLAY_FORWARD, 0.1f) && this->ar_replay_pos <= 0)
264  {
265  this->ar_replay_pos++;
266  }
267  if (App::GetInputEngine()->getEventBoolValueBounce(EV_COMMON_REPLAY_BACKWARD, 0.1f) && this->ar_replay_pos > -this->getNumFrames())
268  {
269  this->ar_replay_pos--;
270  }
271  if (App::GetInputEngine()->getEventBoolValueBounce(EV_COMMON_REPLAY_FAST_FORWARD, 0.1f) && this->ar_replay_pos + 10 <= 0)
272  {
273  this->ar_replay_pos += 10;
274  }
275  if (App::GetInputEngine()->getEventBoolValueBounce(EV_COMMON_REPLAY_FAST_BACKWARD, 0.1f) && this->ar_replay_pos - 10 > -this->getNumFrames())
276  {
277  this->ar_replay_pos -= 10;
278  }
279 
280  if (App::GetInputEngine()->isKeyDown(OIS::KC_LMENU))
281  {
282  if (this->ar_replay_pos <= 0 && this->ar_replay_pos >= -this->getNumFrames())
283  {
284  if (App::GetInputEngine()->isKeyDown(OIS::KC_LSHIFT) || App::GetInputEngine()->isKeyDown(OIS::KC_RSHIFT))
285  {
286  this->ar_replay_pos += App::GetInputEngine()->getMouseState().X.rel * 1.5f;
287  }
288  else
289  {
290  this->ar_replay_pos += App::GetInputEngine()->getMouseState().X.rel * 0.05f;
291  }
292  if (this->ar_replay_pos > 0)
293  {
294  this->ar_replay_pos = 0;
295  }
296  if (this->ar_replay_pos < -this->getNumFrames())
297  {
298  this->ar_replay_pos = -this->getNumFrames();
299  }
300  }
301  }
302  }
303 }
GameContext.h
Game state manager and message-queue provider.
RoR::EV_COMMON_REPLAY_FORWARD
@ EV_COMMON_REPLAY_FORWARD
Definition: InputEngine.h:255
RoR::App::sim_replay_stepping
CVar * sim_replay_stepping
Definition: Application.cpp:103
y
float y
Definition: (ValueTypes) quaternion.h:6
RoR::Actor::ar_num_nodes
int ar_num_nodes
Definition: Actor.h:277
RoR::InputEngine::getMouseState
OIS::MouseState getMouseState()
Definition: InputEngine.cpp:603
RoR::node_simple_t::position
Ogre::Vector3 position
Definition: Replay.h:29
Utils.h
Language.h
RoR::beam_simple_t::disabled
bool disabled
Definition: Replay.h:36
RefCountingObjectPtr< Actor >
GUIManager.h
ActorManager.h
Actor.h
Replay.h
RoR::beam_simple_t
Definition: Replay.h:33
Script2Game::KC_LSHIFT
enum Script2Game::inputEvents KC_LSHIFT
TOSTRING
#define TOSTRING(x)
Definition: Application.h:56
RoR::EV_COMMON_REPLAY_BACKWARD
@ EV_COMMON_REPLAY_BACKWARD
Definition: InputEngine.h:252
RoR::node_simple_t::velocity
Ogre::Vector3 velocity
Definition: Replay.h:30
RoR::EV_COMMON_REPLAY_FAST_FORWARD
@ EV_COMMON_REPLAY_FAST_FORWARD
Definition: InputEngine.h:254
Application.h
Central state/object manager and communications hub.
RoR::EV_COMMON_TOGGLE_REPLAY_MODE
@ EV_COMMON_TOGGLE_REPLAY_MODE
toggle replay mode
Definition: InputEngine.h:270
RoR::EV_COMMON_REPLAY_FAST_BACKWARD
@ EV_COMMON_REPLAY_FAST_BACKWARD
Definition: InputEngine.h:253
RoR::Actor::ar_num_beams
int ar_num_beams
Definition: Actor.h:282
Script2Game::KC_RSHIFT
enum Script2Game::inputEvents KC_RSHIFT
PHYSICS_DT
#define PHYSICS_DT
Definition: SimConstants.h:20
nodes
or anywhere else will not be considered a but parsed as regular data ! Each line is treated as values separated by separators Possible i e animators Multiline description Single does not affect it Directive usualy set global attributes or change behavior of the parsing Directive may appear in any block section Modularity The elements can be grouped into modules Each module must belong to one or more configurations Directives sectionconfig specify truck configurations the user can choose from Exactly one must be selected If the first defined is used lettercase matches original docs(parsing is insensitive). NAME TYPE NOTES advdrag BLOCK add_animation DIRECTIVE Special syntax airbrakes BLOCK animators BLOCK Special syntax IF(values[0]=="") bad trailing chars are silently ignored no space at the end Items delimited On each side of there is max item Empty invalid string parses as node num items Acceptable item the node is the others When a node range has more than nodes
Definition: ReadMe.txt:302
RoR::App::GetInputEngine
InputEngine * GetInputEngine()
Definition: Application.cpp:271
InputEngine.h
Handles controller inputs from player. Defines input events and binding mechanism,...
Ogre
Definition: ExtinguishableFireAffector.cpp:35
RoR::CVar::getInt
int getInt() const
Definition: CVar.h:97
RoR::beam_simple_t::broken
bool broken
Definition: Replay.h:35
RoR::node_simple_t
Definition: Replay.h:27
RoR
Definition: AppContext.h:36
x
float x
Definition: (ValueTypes) quaternion.h:5