1 /*
2  Bullet Continuous Collision Detection and Physics Library
3  Copyright (c) 2015 Google Inc. http://bulletphysics.org
4 
5  This software is provided 'as-is', without any express or implied warranty.
6  In no event will the authors be held liable for any damages arising from the use of this software.
7  Permission is granted to anyone to use this software for any purpose,
8  including commercial applications, and to alter it and redistribute it freely,
9  subject to the following restrictions:
10 
11  1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required.
12  2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software.
13  3. This notice may not be removed or altered from any source distribution.
14  */
15 
16 #ifndef NN3D_WALKERS_TIME_WARP_BASE_H
17 #define NN3D_WALKERS_TIME_WARP_BASE_H
18 
19 #include "btBulletDynamicsCommon.h"
20 #include "LinearMath/btVector3.h"
21 #include "LinearMath/btAlignedObjectArray.h"
22 #include "LinearMath/btQuickprof.h"  // Use your own timer, this timer is only used as we lack another timer
23 
24 #include "../CommonInterfaces/CommonRigidBodyBase.h"
25 #include "../CommonInterfaces/CommonParameterInterface.h"
26 
27 //Solvers
28 #include "BulletDynamics/ConstraintSolver/btSequentialImpulseConstraintSolver.h"
29 #include "BulletDynamics/ConstraintSolver/btNNCGConstraintSolver.h"
30 #include "BulletDynamics/Featherstone/btMultiBodyConstraintSolver.h"
31 #include "BulletDynamics/Featherstone/btMultiBodyDynamicsWorld.h"
32 #include "BulletDynamics/MLCPSolvers/btDantzigSolver.h"
33 #include "BulletDynamics/MLCPSolvers/btSolveProjectedGaussSeidel.h"
34 #include "BulletDynamics/MLCPSolvers/btLemkeSolver.h"
35 #include "BulletDynamics/MLCPSolvers/btMLCPSolver.h"
36 
37 #include "../Utils/b3ERPCFMHelper.hpp"  // ERP/CFM setting utils
38 
39 static btScalar gSimulationSpeed = 1;  // default simulation speed at startup
40 
41 // the current simulation speeds to choose from (the slider will snap to those using a custom form of snapping)
42 namespace SimulationSpeeds
43 {
44 static double /*0*/ PAUSE = 0;
45 static double /*1*/ QUARTER_SPEED = 0.25;
46 static double /*2*/ HALF_SPEED = 0.5;
47 static double /*3*/ NORMAL_SPEED = 1;
48 static double /*4*/ DOUBLE_SPEED = 2;
49 static double /*5*/ QUADRUPLE_SPEED = 4;
50 static double /*6*/ DECUPLE_SPEED = 10;
51 static double /*7*/ CENTUPLE_SPEED = 100;
52 static double /*8*/ QUINCENTUPLE_SPEED = 500;
53 static double /*9*/ MILLITUPLE_SPEED = 1000;
54 static double /*0*/ MAX_SPEED = MILLITUPLE_SPEED;
55 static double /**/ NUM_SPEEDS = 10;
56 };  // namespace SimulationSpeeds
57 
58 // add speeds from the namespace here
59 static double speeds[] = {
60 	SimulationSpeeds::PAUSE,
61 	SimulationSpeeds::QUARTER_SPEED, SimulationSpeeds::HALF_SPEED,
62 	SimulationSpeeds::NORMAL_SPEED, SimulationSpeeds::DOUBLE_SPEED,
63 	SimulationSpeeds::QUADRUPLE_SPEED, SimulationSpeeds::DECUPLE_SPEED,
64 	SimulationSpeeds::CENTUPLE_SPEED, SimulationSpeeds::QUINCENTUPLE_SPEED,
65 	SimulationSpeeds::MILLITUPLE_SPEED};
66 
67 static btScalar gSolverIterations = 10;  // default number of solver iterations for the iterative solvers
68 
69 static bool gIsHeadless = false;  // demo runs with graphics by default
70 
71 static bool gChangeErpCfm = false;  // flag to make recalculation of ERP/CFM
72 
73 static int gMinSpeed = SimulationSpeeds::PAUSE;  // the minimum simulation speed
74 
75 static int gMaxSpeed = SimulationSpeeds::MAX_SPEED;  // the maximum simulation speed
76 
77 static bool gMaximumSpeed = false;  // the demo does not try to achieve maximum stepping speed by default
78 
79 static bool gInterpolate = false;  // the demo does not use any bullet interpolated physics substeps
80 
81 static bool useSplitImpulse = true;  // split impulse fixes issues with restitution in Baumgarte stabilization
82 // http://bulletphysics.org/Bullet/phpBB3/viewtopic.php?f=9&t=7117&p=24631&hilit=Baumgarte#p24631
83 // disabling continuous collision detection can also fix issues with restitution, though CCD is disabled by default an only kicks in at higher speeds
84 // set CCD speed threshold and testing sphere radius per rigidbody (rb->setCCDSpeedThreshold())
85 
86 // all supported solvers by bullet
87 enum SolverEnumType
88 {
89 	SEQUENTIALIMPULSESOLVER = 0,
90 	GAUSSSEIDELSOLVER = 1,
91 	NNCGSOLVER = 2,
92 	DANZIGSOLVER = 3,
93 	LEMKESOLVER = 4,
94 
95 	NUM_SOLVERS = 6
96 };
97 
98 // solvers can be changed by drop down menu
99 namespace SolverType
100 {
101 static char SEQUENTIALIMPULSESOLVER[] = "Sequential Impulse Solver";
102 static char GAUSSSEIDELSOLVER[] = "Gauss-Seidel Solver";
103 static char NNCGSOLVER[] = "NNCG Solver";
104 static char DANZIGSOLVER[] = "Danzig Solver";
105 static char LEMKESOLVER[] = "Lemke Solver";
106 
107 };  // namespace SolverType
108 
109 static const char* solverTypes[NUM_SOLVERS];
110 
111 static SolverEnumType SOLVER_TYPE = SEQUENTIALIMPULSESOLVER;  // You can switch the solver here
112 
113 //TODO:s===
114 //TODO: Give specific explanations about solver values
115 
116 /**
117  * Step size of the bullet physics simulator (solverAccuracy). Accuracy versus speed.
118  */
119 // Choose an appropriate number of steps per second for your needs
120 static btScalar gPhysicsStepsPerSecond = 60.0f;  // Default number of steps
121 //static btScalar gPhysicsStepsPerSecond = 120.0f; // Double steps for more accuracy
122 //static btScalar gPhysicsStepsPerSecond = 240.0f; // For high accuracy
123 //static btScalar gPhysicsStepsPerSecond = 1000.0f; // Very high accuracy
124 
125 // appropriate inverses for seconds and milliseconds
126 static double fixedPhysicsStepSizeSec = 1.0f / gPhysicsStepsPerSecond;       // steps size in seconds
127 static double fixedPhysicsStepSizeMilli = 1000.0f / gPhysicsStepsPerSecond;  // step size in milliseconds
128 
129 static btScalar gApplicationFrequency = 60.0f;                  // number of internal application ticks per second
130 static int gApplicationTick = 1000.0f / gApplicationFrequency;  //ms
131 
132 static btScalar gFramesPerSecond = 30.0f;  // number of frames per second
133 
134 static btScalar gERPSpringK = 10;
135 static btScalar gERPDamperC = 1;
136 
137 static btScalar gCFMSpringK = 10;
138 static btScalar gCFMDamperC = 1;
139 static btScalar gCFMSingularityAvoidance = 0;
140 
141 //GUI related parameter changing helpers
142 
twxChangePhysicsStepsPerSecond(float physicsStepsPerSecond,void *)143 inline void twxChangePhysicsStepsPerSecond(float physicsStepsPerSecond, void*)
144 {  // function to change simulation physics steps per second
145 	gPhysicsStepsPerSecond = physicsStepsPerSecond;
146 }
147 
twxChangeFPS(float framesPerSecond,void *)148 inline void twxChangeFPS(float framesPerSecond, void*)
149 {
150 	gFramesPerSecond = framesPerSecond;
151 }
152 
twxChangeERPCFM(float notUsed,void *)153 inline void twxChangeERPCFM(float notUsed, void*)
154 {  // function to change ERP/CFM appropriately
155 	gChangeErpCfm = true;
156 }
157 
changeSolver(int comboboxId,const char * item,void * userPointer)158 inline void changeSolver(int comboboxId, const char* item, void* userPointer)
159 {  // function to change the solver
160 	for (int i = 0; i < NUM_SOLVERS; i++)
161 	{
162 		if (strcmp(solverTypes[i], item) == 0)
163 		{  // if the strings are equal
164 			SOLVER_TYPE = ((SolverEnumType)i);
165 			b3Printf("=%s=\n Reset the simulation by double clicking it in the menu list.", item);
166 			return;
167 		}
168 	}
169 	b3Printf("No Change");
170 }
171 
twxChangeSolverIterations(float notUsed,void * userPtr)172 inline void twxChangeSolverIterations(float notUsed, void* userPtr)
173 {  // change the solver iterations
174 }
175 
clampToCustomSpeedNotches(float speed,void *)176 inline void clampToCustomSpeedNotches(float speed, void*)
177 {  // function to clamp to custom speed notches
178 	double minSpeed = 0;
179 	double minSpeedDist = SimulationSpeeds::MAX_SPEED;
180 	for (int i = 0; i < SimulationSpeeds::NUM_SPEEDS; i++)
181 	{
182 		double speedDist = (speeds[i] - speed >= 0) ? speeds[i] - speed : speed - speeds[i];  // float absolute
183 
184 		if (minSpeedDist > speedDist)
185 		{
186 			minSpeedDist = speedDist;
187 			minSpeed = speeds[i];
188 		}
189 	}
190 	gSimulationSpeed = minSpeed;
191 }
192 
switchInterpolated(int buttonId,bool buttonState,void * userPointer)193 inline void switchInterpolated(int buttonId, bool buttonState, void* userPointer)
194 {  // toggle if interpolation steps are taken
195 	gInterpolate = !gInterpolate;
196 	//	b3Printf("Interpolate substeps %s", gInterpolate?"on":"off");
197 }
198 
switchHeadless(int buttonId,bool buttonState,void * userPointer)199 inline void switchHeadless(int buttonId, bool buttonState, void* userPointer)
200 {  // toggle if the demo should run headless
201 	gIsHeadless = !gIsHeadless;
202 	//	b3Printf("Run headless %s", gIsHeadless?"on":"off");
203 }
204 
switchMaximumSpeed(int buttonId,bool buttonState,void * userPointer)205 inline void switchMaximumSpeed(int buttonId, bool buttonState, void* userPointer)
206 {   // toggle it the demo should run as fast as possible
207 	//	b3Printf("Run maximum speed %s", gMaximumSpeed?"on":"off");
208 }
209 
setApplicationTick(float frequency,void *)210 inline void setApplicationTick(float frequency, void*)
211 {  // set internal application tick
212 	gApplicationTick = 1000.0f / frequency;
213 }
214 
215 /**
216  * @link: Gaffer on Games - Fix your timestep: http://gafferongames.com/game-physics/fix-your-timestep/
217  */
218 struct NN3DWalkersTimeWarpBase : public CommonRigidBodyBase
219 {
NN3DWalkersTimeWarpBaseNN3DWalkersTimeWarpBase220 	NN3DWalkersTimeWarpBase(struct GUIHelperInterface* helper) : CommonRigidBodyBase(helper),
221 																 mPhysicsStepsPerSecondUpdated(false),
222 																 mFramesPerSecondUpdated(false),
223 																 mSolverIterationsUpdated(false)
224 	{
225 		// main frame timer initialization
226 		mApplicationStart = mLoopTimer.getTimeMilliseconds(); /**!< Initialize when the application started running */
227 		mInputClock = mApplicationStart;                      /**!< Initialize the last time the input was updated */
228 		mPreviousModelIteration = mApplicationStart;
229 		mThisModelIteration = mApplicationStart;
230 		mApplicationRuntime = mThisModelIteration - mApplicationStart; /**!< Initialize the application runtime */
231 
232 		// sub frame time initializations
233 		mGraphicsStart = mApplicationStart; /** !< Initialize the last graphics start */
234 		mModelStart = mApplicationStart;    /** !< Initialize the last model start */
235 		mInputStart = mApplicationStart;    /** !< Initialize the last input start */
236 
237 		mPhysicsStepStart = mApplicationStart; /**!< Initialize the physics step start */
238 		mPhysicsStepEnd = mApplicationStart;   /**!< Initialize the physics step end */
239 
240 		//durations
241 		mLastGraphicsTick = 0;
242 		mLastModelTick = 0;
243 		mLastInputTick = 0;
244 		mPhysicsTick = 0;
245 
246 		mInputDt = 0;
247 		mModelAccumulator = 0;
248 		mFrameTime = 0;
249 
250 		fpsTimeStamp = mLoopTimer.getTimeMilliseconds();  // to time the fps
251 		fpsStep = 1000.0f / gFramesPerSecond;
252 
253 		// performance measurements for this demo
254 		performanceTimestamp = 0;
255 		performedTime = 0;                                    // time the physics steps consumed
256 		speedUpPrintTimeStamp = mLoopTimer.getTimeSeconds();  // timer to print the speed up periodically
257 		mLoopTimer.reset();
258 	}
259 
~NN3DWalkersTimeWarpBaseNN3DWalkersTimeWarpBase260 	~NN3DWalkersTimeWarpBase()
261 	{
262 	}
263 
initPhysicsNN3DWalkersTimeWarpBase264 	void initPhysics()
265 	{  // initialize the demo
266 
267 		setupBasicParamInterface();  // setup adjustable sliders and buttons for parameters
268 
269 		m_guiHelper->setUpAxis(1);  // Set Y axis as Up axis
270 
271 		createEmptyDynamicsWorld();  // create an empty dynamic world
272 
273 		m_guiHelper->autogenerateGraphicsObjects(m_dynamicsWorld);
274 	}
275 
setupBasicParamInterfaceNN3DWalkersTimeWarpBase276 	void setupBasicParamInterface()
277 	{  // setup the adjustable sliders and button for parameters
278 
279 		{  // create a slider to adjust the simulation speed
280 			// Force increase the simulation speed to run the simulation with the same accuracy but a higher speed
281 			SliderParams slider("Simulation speed",
282 								&gSimulationSpeed);
283 			slider.m_minVal = gMinSpeed;
284 			slider.m_maxVal = gMaxSpeed;
285 			slider.m_callback = clampToCustomSpeedNotches;
286 			slider.m_clampToNotches = false;
287 			if (m_guiHelper->getParameterInterface())
288 				m_guiHelper->getParameterInterface()->registerSliderFloatParameter(
289 					slider);
290 		}
291 
292 		{  // create a button to switch to headless simulation
293 			// This turns off the graphics update and therefore results in more time for the model update
294 			ButtonParams button("Run headless", 0, true);
295 			button.m_callback = switchHeadless;
296 			if (m_guiHelper->getParameterInterface())
297 				m_guiHelper->getParameterInterface()->registerButtonParameter(
298 					button);
299 		}
300 
301 		{  // create a button to switch to maximum speed simulation (fully deterministic)
302 			// Interesting to test the maximal achievable speed on this hardware
303 			ButtonParams button("Run maximum speed", 0, true);
304 			button.m_callback = switchMaximumSpeed;
305 			if (m_guiHelper->getParameterInterface())
306 				m_guiHelper->getParameterInterface()->registerButtonParameter(
307 					button);
308 		}
309 
310 		{  // create a button to switch bullet to perform interpolated substeps to speed up simulation
311 			// generally, interpolated steps are a good speed-up and should only be avoided if higher accuracy is needed (research purposes etc.)
312 			ButtonParams button("Perform interpolated substeps", 0, true);
313 			button.m_callback = switchInterpolated;
314 			if (m_guiHelper->getParameterInterface())
315 				m_guiHelper->getParameterInterface()->registerButtonParameter(
316 					button);
317 		}
318 	}
319 
setupAdvancedParamInterfaceNN3DWalkersTimeWarpBase320 	void setupAdvancedParamInterface()
321 	{
322 		solverTypes[0] = SolverType::SEQUENTIALIMPULSESOLVER;
323 		solverTypes[1] = SolverType::GAUSSSEIDELSOLVER;
324 		solverTypes[2] = SolverType::NNCGSOLVER;
325 		solverTypes[3] = SolverType::DANZIGSOLVER;
326 		solverTypes[4] = SolverType::LEMKESOLVER;
327 
328 
329 		{
330 			ComboBoxParams comboParams;
331 			comboParams.m_comboboxId = 0;
332 			comboParams.m_numItems = NUM_SOLVERS;
333 			comboParams.m_startItem = SOLVER_TYPE;
334 			comboParams.m_callback = changeSolver;
335 
336 			comboParams.m_items = solverTypes;
337 			m_guiHelper->getParameterInterface()->registerComboBox(comboParams);
338 		}
339 
340 		{  // create a slider to adjust the number of internal application ticks
341 			// The set application tick should contain enough time to perform a full cycle of model update (physics and input)
342 			// and view update (graphics) with average application load. The graphics and input update determine the remaining time
343 			// for the physics update
344 			SliderParams slider("Application Ticks",
345 								&gApplicationFrequency);
346 			slider.m_minVal = gMinSpeed;
347 			slider.m_maxVal = gMaxSpeed;
348 			slider.m_callback = setApplicationTick;
349 			slider.m_clampToNotches = false;
350 			if (m_guiHelper->getParameterInterface())
351 				m_guiHelper->getParameterInterface()->registerSliderFloatParameter(
352 					slider);
353 		}
354 
355 		{  // create a slider to adjust the number of physics steps per second
356 			// The default number of steps is at 60, which is appropriate for most general simulations
357 			// For simulations with higher complexity or if you experience undesired behavior, try increasing the number of steps per second
358 			// Alternatively, try increasing the number of solver iterations if you experience jittering constraints due to non-converging solutions
359 			SliderParams slider("Physics steps per second", &gPhysicsStepsPerSecond);
360 			slider.m_minVal = 0;
361 			slider.m_maxVal = 1000;
362 			slider.m_callback = twxChangePhysicsStepsPerSecond;
363 			slider.m_clampToNotches = false;
364 			if (m_guiHelper->getParameterInterface())
365 				m_guiHelper->getParameterInterface()->registerSliderFloatParameter(
366 					slider);
367 		}
368 
369 		{  // create a slider to adjust the number of frames per second
370 			SliderParams slider("Frames per second", &gFramesPerSecond);
371 			slider.m_minVal = 0;
372 			slider.m_maxVal = 200;
373 			slider.m_callback = twxChangeFPS;
374 			slider.m_clampToNotches = false;
375 			if (m_guiHelper->getParameterInterface())
376 				m_guiHelper->getParameterInterface()->registerSliderFloatParameter(
377 					slider);
378 		}
379 
380 		{  // create a slider to adjust the number of solver iterations to converge to a solution
381 			// more complex simulations might need a higher number of iterations to converge, it also
382 			// depends on the type of solver.
383 			SliderParams slider(
384 				"Solver interations",
385 				&gSolverIterations);
386 			slider.m_minVal = 0;
387 			slider.m_maxVal = 1000;
388 			slider.m_callback = twxChangePhysicsStepsPerSecond;
389 			slider.m_clampToIntegers = true;
390 			m_guiHelper->getParameterInterface()->registerSliderFloatParameter(
391 				slider);
392 		}
393 
394 		// ERP/CFM sliders
395 		// Advanced users: Check descriptions of ERP/CFM in BulletUtils.cpp
396 
397 		{  // create a slider to adjust ERP Spring k constant
398 			SliderParams slider("Global ERP Spring k (F=k*x)", &gERPSpringK);
399 			slider.m_minVal = 0;
400 			slider.m_maxVal = 10;
401 			slider.m_callback = twxChangeERPCFM;
402 			slider.m_clampToNotches = false;
403 			if (m_guiHelper->getParameterInterface())
404 				m_guiHelper->getParameterInterface()->registerSliderFloatParameter(
405 					slider);
406 		}
407 
408 		{  // create a slider to adjust ERP damper c constant
409 			SliderParams slider("Global ERP damper c (F=c*xdot)", &gERPDamperC);
410 			slider.m_minVal = 0;
411 			slider.m_maxVal = 10;
412 			slider.m_callback = twxChangeERPCFM;
413 			slider.m_clampToNotches = false;
414 			if (m_guiHelper->getParameterInterface())
415 				m_guiHelper->getParameterInterface()->registerSliderFloatParameter(
416 					slider);
417 		}
418 
419 		{  // create a slider to adjust CFM Spring k constant
420 			SliderParams slider("Global CFM Spring k (F=k*x)", &gCFMSpringK);
421 			slider.m_minVal = 0;
422 			slider.m_maxVal = 10;
423 			slider.m_callback = twxChangeERPCFM;
424 			slider.m_clampToNotches = false;
425 			if (m_guiHelper->getParameterInterface())
426 				m_guiHelper->getParameterInterface()->registerSliderFloatParameter(
427 					slider);
428 		}
429 
430 		{  // create a slider to adjust CFM damper c constant
431 			SliderParams slider("Global CFM damper c (F=c*xdot)", &gCFMDamperC);
432 			slider.m_minVal = 0;
433 			slider.m_maxVal = 10;
434 			slider.m_callback = twxChangeERPCFM;
435 			slider.m_clampToNotches = false;
436 			if (m_guiHelper->getParameterInterface())
437 				m_guiHelper->getParameterInterface()->registerSliderFloatParameter(
438 					slider);
439 		}
440 
441 		{  // create a slider to adjust CFM damper c constant
442 			SliderParams slider("Global CFM singularity avoidance", &gCFMSingularityAvoidance);
443 			slider.m_minVal = 0;
444 			slider.m_maxVal = 10;
445 			slider.m_callback = twxChangeERPCFM;
446 			slider.m_clampToNotches = false;
447 			if (m_guiHelper->getParameterInterface())
448 				m_guiHelper->getParameterInterface()->registerSliderFloatParameter(
449 					slider);
450 		}
451 	}
452 
createEmptyDynamicsWorldNN3DWalkersTimeWarpBase453 	void createEmptyDynamicsWorld()
454 	{  // create an empty dynamics worlds according to the chosen settings via statics (top section of code)
455 
456 		///collision configuration contains default setup for memory, collision setup
457 		m_collisionConfiguration = new btDefaultCollisionConfiguration();
458 		//m_collisionConfiguration->setConvexConvexMultipointIterations();
459 
460 		///use the default collision dispatcher. For parallel processing you can use a diffent dispatcher (see Extras/BulletMultiThreaded)
461 		m_dispatcher = new btCollisionDispatcher(m_collisionConfiguration);
462 
463 		// default broadphase
464 		m_broadphase = new btDbvtBroadphase();
465 
466 		// different solvers require different settings
467 		switch (SOLVER_TYPE)
468 		{
469 			case SEQUENTIALIMPULSESOLVER:
470 			{
471 				//			b3Printf("=%s=",SolverType::SEQUENTIALIMPULSESOLVER);
472 				m_solver = new btSequentialImpulseConstraintSolver();
473 				break;
474 			}
475 			case NNCGSOLVER:
476 			{
477 				//			b3Printf("=%s=",SolverType::NNCGSOLVER);
478 				m_solver = new btNNCGConstraintSolver();
479 				break;
480 			}
481 			case DANZIGSOLVER:
482 			{
483 				//			b3Printf("=%s=",SolverType::DANZIGSOLVER);
484 				btDantzigSolver* mlcp = new btDantzigSolver();
485 				m_solver = new btMLCPSolver(mlcp);
486 				break;
487 			}
488 			case GAUSSSEIDELSOLVER:
489 			{
490 				//			b3Printf("=%s=",SolverType::GAUSSSEIDELSOLVER);
491 				btSolveProjectedGaussSeidel* mlcp = new btSolveProjectedGaussSeidel();
492 				m_solver = new btMLCPSolver(mlcp);
493 				break;
494 			}
495 			case LEMKESOLVER:
496 			{
497 				//			b3Printf("=%s=",SolverType::LEMKESOLVER);
498 				btLemkeSolver* mlcp = new btLemkeSolver();
499 				m_solver = new btMLCPSolver(mlcp);
500 				break;
501 			}
502 
503 			default:
504 				break;
505 		}
506 
507 		if (1)
508 		{
509 			//TODO: Set parameters for other solvers
510 
511 			m_dynamicsWorld = new btDiscreteDynamicsWorld(m_dispatcher,
512 														  m_broadphase, m_solver, m_collisionConfiguration);
513 
514 			if (SOLVER_TYPE == DANZIGSOLVER || SOLVER_TYPE == GAUSSSEIDELSOLVER)
515 			{
516 				m_dynamicsWorld->getSolverInfo().m_minimumSolverBatchSize = 1;  //for mlcp solver it is better to have a small A matrix
517 			}
518 			else
519 			{
520 				m_dynamicsWorld->getSolverInfo().m_minimumSolverBatchSize = 128;  //for direct solver, it is better to solve multiple objects together, small batches have high overhead
521 			}
522 
523 			m_dynamicsWorld->getDispatchInfo().m_useContinuous = true;  // set continuous collision
524 		}
525 		else
526 		{
527 			//use btMultiBodyDynamicsWorld for Featherstone btMultiBody support
528 			m_dynamicsWorld = new btMultiBodyDynamicsWorld(m_dispatcher,
529 														   m_broadphase, (btMultiBodyConstraintSolver*)m_solver,
530 														   m_collisionConfiguration);
531 		}
532 
533 		changeERPCFM();  // set appropriate ERP/CFM values according to the string and damper properties of the constraint
534 
535 		if (useSplitImpulse)
536 		{                                                         // If you experience strong repulsion forces in your constraints, it might help to enable the split impulse feature
537 			m_dynamicsWorld->getSolverInfo().m_splitImpulse = 1;  //enable split impulse feature
538 																  //		m_dynamicsWorld->getSolverInfo().m_splitImpulsePenetrationThreshold =
539 																  //			-0.02;
540 																  //		m_dynamicsWorld->getSolverInfo().m_erp2 = BulletUtils::getERP(
541 																  //			fixedPhysicsStepSizeSec, 10, 1);
542 																  //		m_dynamicsWorld->getSolverInfo().m_splitImpulseTurnErp =
543 																  //			BulletUtils::getERP(fixedPhysicsStepSizeSec, 10, 1);
544 																  //			b3Printf("Using split impulse feature with ERP/TurnERP: (%f,%f)",
545 																  //				m_dynamicsWorld->getSolverInfo().m_erp2,
546 																  //				m_dynamicsWorld->getSolverInfo().m_splitImpulseTurnErp);
547 		}
548 
549 		m_dynamicsWorld->getSolverInfo().m_numIterations = gSolverIterations;  // set the number of solver iterations for iteration based solvers
550 
551 		m_dynamicsWorld->setGravity(btVector3(0, -9.81f, 0));  // set gravity to -9.81
552 	}
553 
calculatePerformedSpeedupNN3DWalkersTimeWarpBase554 	btScalar calculatePerformedSpeedup()
555 	{  // calculate performed speedup
556 		// we calculate the performed speed up
557 		btScalar speedUp = ((double)performedTime * 1000.0) / ((double)(mLoopTimer.getTimeMilliseconds() - performanceTimestamp));
558 		//		b3Printf("Avg Effective speedup: %f",speedUp);
559 		performedTime = 0;
560 		performanceTimestamp = mLoopTimer.getTimeMilliseconds();
561 		return speedUp;
562 	}
563 
timeWarpSimulationNN3DWalkersTimeWarpBase564 	void timeWarpSimulation(float deltaTime)  // Override this
565 	{
566 	}
567 
stepSimulationNN3DWalkersTimeWarpBase568 	void stepSimulation(float deltaTime)
569 	{  // customly step the simulation
570 		do
571 		{
572 			//			// settings
573 			if (mPhysicsStepsPerSecondUpdated)
574 			{
575 				changePhysicsStepsPerSecond(gPhysicsStepsPerSecond);
576 				mPhysicsStepsPerSecondUpdated = false;
577 			}
578 
579 			if (mFramesPerSecondUpdated)
580 			{
581 				changeFPS(gFramesPerSecond);
582 				mFramesPerSecondUpdated = false;
583 			}
584 
585 			if (gChangeErpCfm)
586 			{
587 				changeERPCFM();
588 				gChangeErpCfm = false;
589 			}
590 
591 			if (mSolverIterationsUpdated)
592 			{
593 				changeSolverIterations(gSolverIterations);
594 				mSolverIterationsUpdated = false;
595 			}
596 
597 			// structure according to the canonical game loop
598 			// http://www.bulletphysics.org/mediawiki-1.5.8/index.php/Canonical_Game_Loop
599 
600 			//##############
601 			// breaking conditions - if the loop should stop, then check it here
602 
603 			//#############
604 			// model update - here you perform updates of your model, be it the physics model, the game or simulation state or anything not related to graphics and input
605 
606 			timeWarpSimulation(deltaTime);
607 			if (mLoopTimer.getTimeSeconds() - speedUpPrintTimeStamp > 1)
608 			{
609 				// on reset, we calculate the performed speed up
610 				//double speedUp = ((double)performedTime*1000.0)/((double)(mLoopTimer.getTimeMilliseconds()-performanceTimestamp));
611 				//				b3Printf("Avg Effective speedup: %f",speedUp);
612 				performedTime = 0;
613 				performanceTimestamp = mLoopTimer.getTimeMilliseconds();
614 				speedUpPrintTimeStamp = mLoopTimer.getTimeSeconds();
615 			}
616 
617 			// update timers
618 			mThisModelIteration = mLoopTimer.getTimeMilliseconds();
619 			mFrameTime = mThisModelIteration - mPreviousModelIteration; /**!< Calculate the frame time (in Milliseconds) */
620 			mPreviousModelIteration = mThisModelIteration;
621 
622 			//	b3Printf("Current Frame time: % u", mFrameTime);
623 
624 			mApplicationRuntime = mThisModelIteration - mApplicationStart; /**!< Update main frame timer (in Milliseconds) */
625 
626 			mModelStart = mLoopTimer.getTimeMilliseconds();   /**!< Begin with the model update (in Milliseconds)*/
627 			mLastGraphicsTick = mModelStart - mGraphicsStart; /**!< Update graphics timer (in Milliseconds) */
628 
629 			if (gMaximumSpeed /** If maximum speed is enabled*/)
630 			{
631 				performMaxStep();
632 			}
633 			else
634 			{ /**!< This mode tries to progress as much time as it is expected from the game loop*/
635 				performSpeedStep();
636 			}
637 
638 			mInputStart = mLoopTimer.getTimeMilliseconds(); /**!< Start the input update */
639 			mLastModelTick = mInputStart - mModelStart;     /**!< Calculate the time the model update took */
640 
641 			//#############
642 			// Input update - Game Clock part of the loop
643 			/** This runs once every gApplicationTick milliseconds on average */
644 			mInputDt = mThisModelIteration - mInputClock;
645 			if (mInputDt >= gApplicationTick)
646 			{
647 				mInputClock = mThisModelIteration;
648 				//	         mInputHandler.injectInput(); /**!< Inject input into handlers */
649 				//	         mInputHandler.update(mInputClock); /**!< update elements that work on the current input state */
650 			}
651 
652 			mGraphicsStart = mLoopTimer.getTimeMilliseconds(); /**!< Start the graphics update */
653 			mLastInputTick = mGraphicsStart - mInputStart;     /**!< Calculate the time the input injection took */
654 
655 			//#############
656 			// Graphics update - Here you perform the representation of your model, meaning graphics rendering according to what your game or simulation model describes
657 			// In the example browser, there is a separate method called renderScene() for this
658 
659 			// Uncomment this for some detailed output about the application ticks
660 			//	b3Printf(
661 			//		"Physics time: %u milliseconds / Graphics time: %u milliseconds / Input time: %u milliseconds / Total time passed: %u milliseconds",
662 			//		mLastModelTick, mLastGraphicsTick, mLastInputTick, mApplicationRuntime);
663 
664 		} while (mLoopTimer.getTimeMilliseconds() - fpsTimeStamp < fpsStep);  // escape the loop if it is time to render
665 		// Unfortunately, the input is not included in the loop, therefore the input update frequency is equal to the fps
666 
667 		fpsTimeStamp = mLoopTimer.getTimeMilliseconds();
668 	}
669 
keyboardCallbackNN3DWalkersTimeWarpBase670 	virtual bool keyboardCallback(int key, int state)
671 	{
672 		switch (key)
673 		{
674 			case '1':
675 			{
676 				gSimulationSpeed = SimulationSpeeds::QUARTER_SPEED;
677 				gMaximumSpeed = false;
678 				return true;
679 			}
680 			case '2':
681 			{
682 				gSimulationSpeed = SimulationSpeeds::HALF_SPEED;
683 				gMaximumSpeed = false;
684 				return true;
685 			}
686 			case '3':
687 			{
688 				gSimulationSpeed = SimulationSpeeds::NORMAL_SPEED;
689 				gMaximumSpeed = false;
690 				return true;
691 			}
692 			case '4':
693 			{
694 				gSimulationSpeed = SimulationSpeeds::DOUBLE_SPEED;
695 				gMaximumSpeed = false;
696 				return true;
697 			}
698 			case '5':
699 			{
700 				gSimulationSpeed = SimulationSpeeds::QUADRUPLE_SPEED;
701 				gMaximumSpeed = false;
702 				return true;
703 			}
704 			case '6':
705 			{
706 				gSimulationSpeed = SimulationSpeeds::DECUPLE_SPEED;
707 				gMaximumSpeed = false;
708 				return true;
709 			}
710 			case '7':
711 			{
712 				gSimulationSpeed = SimulationSpeeds::CENTUPLE_SPEED;
713 				gMaximumSpeed = false;
714 				return true;
715 			}
716 			case '8':
717 			{
718 				gSimulationSpeed = SimulationSpeeds::QUINCENTUPLE_SPEED;
719 				gMaximumSpeed = false;
720 				return true;
721 			}
722 			case '9':
723 			{
724 				gSimulationSpeed = SimulationSpeeds::MILLITUPLE_SPEED;
725 				gMaximumSpeed = false;
726 				return true;
727 			}
728 			case '0':
729 			{
730 				gSimulationSpeed = SimulationSpeeds::MAX_SPEED;
731 				gMaximumSpeed = true;
732 				return true;
733 			}
734 		}
735 		return CommonRigidBodyBase::keyboardCallback(key, state);
736 	}
737 
changePhysicsStepsPerSecondNN3DWalkersTimeWarpBase738 	void changePhysicsStepsPerSecond(float physicsStepsPerSecond)
739 	{  // change the simulation accuracy
740 		if (m_dynamicsWorld && physicsStepsPerSecond)
741 		{
742 			fixedPhysicsStepSizeSec = 1.0f / physicsStepsPerSecond;
743 			fixedPhysicsStepSizeMilli = 1000.0f / physicsStepsPerSecond;
744 
745 			changeERPCFM();
746 		}
747 	}
748 
changeERPCFMNN3DWalkersTimeWarpBase749 	void changeERPCFM()
750 	{  // Change ERP/CFM appropriately to the timestep and the ERP/CFM parameters above
751 		if (m_dynamicsWorld)
752 		{
753 			m_dynamicsWorld->getSolverInfo().m_erp = b3ERPCFMHelper::getERP(  // set the error reduction parameter
754 				fixedPhysicsStepSizeSec,                                      // step size per second
755 				gERPSpringK,                                                  // k of a spring in the equation F = k * x (x:position)
756 				gERPDamperC);                                                 // k of a damper in the equation F = k * v (v:velocity)
757 
758 			m_dynamicsWorld->getSolverInfo().m_globalCfm = b3ERPCFMHelper::getCFM(  // set the constraint force mixing according to the time step
759 				gCFMSingularityAvoidance,                                           // singularity avoidance (if you experience unsolvable constraints, increase this value
760 				fixedPhysicsStepSizeSec,                                            // steps size per second
761 				gCFMSpringK,                                                        // k of a spring in the equation F = k * x (x:position)
762 				gCFMDamperC);                                                       // k of a damper in the equation F = k * v (v:velocity)
763 
764 			//			b3Printf("Bullet DynamicsWorld ERP: %f",
765 			//				m_dynamicsWorld->getSolverInfo().m_erp);
766 
767 			//			b3Printf("Bullet DynamicsWorld CFM: %f",
768 			//				m_dynamicsWorld->getSolverInfo().m_globalCfm);
769 		}
770 	}
771 
changeSolverIterationsNN3DWalkersTimeWarpBase772 	void changeSolverIterations(int iterations)
773 	{  // change the number of iterations
774 		m_dynamicsWorld->getSolverInfo().m_numIterations = iterations;
775 	}
776 
changeFPSNN3DWalkersTimeWarpBase777 	void changeFPS(float framesPerSecond)
778 	{  // change the frames per second
779 		fpsStep = 1000.0f / gFramesPerSecond;
780 	}
781 
performTrueStepsNN3DWalkersTimeWarpBase782 	void performTrueSteps(btScalar timeStep)
783 	{                                                                     // physics stepping without interpolated substeps
784 		int subSteps = floor((timeStep / fixedPhysicsStepSizeSec) + 0.5); /**!< Calculate the number of full normal time steps we can take */
785 
786 		for (int i = 0; i < subSteps; i++)
787 		{ /**!< Perform the number of substeps to reach the timestep*/
788 			if (timeStep && m_dynamicsWorld)
789 			{
790 				// since we want to perform all proper steps, we perform no interpolated substeps
791 				int subSteps = 1;
792 
793 				m_dynamicsWorld->stepSimulation(btScalar(timeStep),
794 												btScalar(subSteps), btScalar(fixedPhysicsStepSizeSec));
795 			}
796 		}
797 	}
798 
performInterpolatedStepsNN3DWalkersTimeWarpBase799 	void performInterpolatedSteps(btScalar timeStep)
800 	{                                                                         // physics stepping with interpolated substeps
801 		int subSteps = 1 + floor((timeStep / fixedPhysicsStepSizeSec) + 0.5); /**!< Calculate the number of full normal time steps we can take, plus 1 for safety of not losing time */
802 		if (timeStep && m_dynamicsWorld)
803 		{
804 			m_dynamicsWorld->stepSimulation(btScalar(timeStep), btScalar(subSteps),
805 											btScalar(fixedPhysicsStepSizeSec)); /**!< Perform the number of substeps to reach the timestep*/
806 		}
807 	}
808 
performMaxStepNN3DWalkersTimeWarpBase809 	void performMaxStep()
810 	{  // perform as many steps as possible
811 		if (gApplicationTick >= mLastGraphicsTick + mLastInputTick)
812 		{                                   // if the remaining time for graphics is going to be positive
813 			mPhysicsTick = gApplicationTick /**!< calculate the remaining time for physics (in Milliseconds) */
814 						   - mLastGraphicsTick - mLastInputTick;
815 		}
816 		else
817 		{
818 			mPhysicsTick = 0;  // no time for physics left / The internal application step is too high
819 		}
820 
821 		//	b3Printf("Application tick: %u",gApplicationTick);
822 		//	b3Printf("Graphics tick: %u",mLastGraphicsTick);
823 		//	b3Printf("Input tick: %u",mLastInputTick);
824 		//	b3Printf("Physics tick: %u",mPhysicsTick);
825 
826 		if (mPhysicsTick > 0)
827 		{  // with positive physics tick we perform as many update steps until the time for it is used up
828 
829 			mPhysicsStepStart = mLoopTimer.getTimeMilliseconds(); /**!< The physics updates start (in Milliseconds)*/
830 			mPhysicsStepEnd = mPhysicsStepStart;
831 
832 			while (mPhysicsTick > mPhysicsStepEnd - mPhysicsStepStart)
833 			{ /**!< Update the physics until we run out of time (in Milliseconds) */
834 				//			b3Printf("Physics passed: %u", mPhysicsStepEnd - mPhysicsStepStart);
835 				double timeStep = fixedPhysicsStepSizeSec; /**!< update the world (in Seconds) */
836 
837 				if (gInterpolate)
838 				{
839 					performInterpolatedSteps(timeStep);
840 				}
841 				else
842 				{
843 					performTrueSteps(timeStep);
844 				}
845 				performedTime += timeStep;
846 				mPhysicsStepEnd = mLoopTimer.getTimeMilliseconds(); /**!< Update the last physics step end to stop updating in time (in Milliseconds) */
847 			}
848 		}
849 	}
850 
performSpeedStepNN3DWalkersTimeWarpBase851 	void performSpeedStep()
852 	{  // force-perform the number of steps needed to achieve a certain speed (safe to too high speeds, meaning the application will lose time, not the physics)
853 		if (mFrameTime > gApplicationTick)
854 		{                                   /** cap frametime to make the application lose time, not the physics (in Milliseconds) */
855 			mFrameTime = gApplicationTick;  // This prevents the physics time accumulator to sum up too much time
856 		}                                   // The simulation therefore gets slower, but still performs all requested physics steps
857 
858 		mModelAccumulator += mFrameTime; /**!< Accumulate the time the physics simulation has to perform in order to stay in real-time (in Milliseconds) */
859 		//	b3Printf("Model time accumulator: %u", mModelAccumulator);
860 
861 		int steps = floor(mModelAccumulator / fixedPhysicsStepSizeMilli); /**!< Calculate the number of time steps we can take */
862 		//	b3Printf("Next steps: %i", steps);
863 
864 		if (steps > 0)
865 		{ /**!< Update if we can take at least one step */
866 
867 			double timeStep = gSimulationSpeed * steps * fixedPhysicsStepSizeSec; /**!< update the universe (in Seconds) */
868 
869 			if (gInterpolate)
870 			{
871 				performInterpolatedSteps(timeStep);  // perform interpolated steps
872 			}
873 			else
874 			{
875 				performTrueSteps(timeStep);  // perform full steps
876 			}
877 			performedTime += timeStep;                              // sum up the performed time for measuring the speed up
878 			mModelAccumulator -= steps * fixedPhysicsStepSizeMilli; /**!< Remove the time performed by the physics simulation from the accumulator, the remaining time carries over to the next cycle  (in Milliseconds) */
879 		}
880 	}
881 
renderSceneNN3DWalkersTimeWarpBase882 	void renderScene()
883 	{  // render the scene
884 		if (!gIsHeadless)
885 		{  // while the simulation is not running headlessly, render to screen
886 			CommonRigidBodyBase::renderScene();
887 
888 			if (m_dynamicsWorld->getDebugDrawer())
889 			{
890 				debugDraw(m_dynamicsWorld->getDebugDrawer()->getDebugMode());
891 			}
892 		}
893 		mIsHeadless = gIsHeadless;
894 	}
resetCameraNN3DWalkersTimeWarpBase895 	void resetCamera()
896 	{  // reset the camera to its original position
897 		float dist = 41;
898 		float pitch = 52;
899 		float yaw = 35;
900 		float targetPos[3] = {0, 0.46, 0};
901 		m_guiHelper->resetCamera(dist, pitch, yaw, targetPos[0], targetPos[1],
902 								 targetPos[2]);
903 	}
904 
905 	// loop timing components ###################
906 	//# loop timestamps
907 	btClock mLoopTimer;                        /**!< The loop timer to time the loop correctly */
908 	unsigned long int mApplicationStart;       /**!< The time the application was started (absolute, in Milliseconds) */
909 	unsigned long int mPreviousModelIteration; /**!< The previous model iteration timestamp (absolute, in Milliseconds) */
910 	unsigned long int mThisModelIteration;     /**!< This model iteration timestamp (absolute, in Milliseconds) */
911 
912 	//# loop durations
913 	long int mModelAccumulator;            /**!< The time to forward the model in this loop iteration (relative, in Milliseconds) */
914 	unsigned long int mFrameTime;          /**!< The time to render a frame (relative, in Milliseconds) */
915 	unsigned long int mApplicationRuntime; /**!< The total application runtime (relative, in Milliseconds) */
916 
917 	long int mInputDt; /**!< The time difference of input that has to be fed in */
918 	unsigned long int mInputClock;
919 
920 	long int mLastGraphicsTick; /*!< The time it took the graphics rendering last time (relative, in Milliseconds) */
921 	unsigned long int mGraphicsStart;
922 
923 	long int mLastInputTick; /**!< The time it took the input to process last time (relative, in Milliseconds) */
924 	unsigned long int mInputStart;
925 
926 	long int mLastModelTick;       /**!<  The time it took the model to update last time
927 	 This includes the bullet physics update */
928 	unsigned long int mModelStart; /**!< The timestamp the model started updating last (absolute, in Milliseconds)*/
929 
930 	long int mPhysicsTick;               /**!< The time remaining in the loop to update the physics (relative, in Milliseconds)*/
931 	unsigned long int mPhysicsStepStart; /**!< The physics start timestamp (absolute, in Milliseconds) */
932 	unsigned long int mPhysicsStepEnd;   /**!< The last physics step end (absolute, in Milliseconds) */
933 
934 	// to measure the performance of the demo
935 	double performedTime;
936 	unsigned long int performanceTimestamp;
937 
938 	unsigned long int speedUpPrintTimeStamp;
939 
940 	unsigned long int fpsTimeStamp; /**!< FPS timing variables */
941 	double fpsStep;
942 
943 	//store old values
944 	bool mPhysicsStepsPerSecondUpdated;
945 	bool mFramesPerSecondUpdated;
946 	bool mSolverIterationsUpdated;
947 	bool mIsHeadless;
948 };
949 
950 #endif  //NN3D_WALKERS_TIME_WARP_BASE_H
951