PageRenderTime 31ms CodeModel.GetById 14ms RepoModel.GetById 0ms app.codeStats 0ms

/CS/migrated/branches/R0_90/apps/demo/demoseq.cpp

#
C++ | 674 lines | 572 code | 48 blank | 54 comment | 89 complexity | b11e6f7ef91de58a7967a58e0fa1bade MD5 | raw file
Possible License(s): GPL-2.0, LGPL-2.1, LGPL-2.0
  1. /*
  2. Copyright (C) 2001 by Jorrit Tyberghein
  3. This library is free software; you can redistribute it and/or
  4. modify it under the terms of the GNU Library General Public
  5. License as published by the Free Software Foundation; either
  6. version 2 of the License, or (at your option) any later version.
  7. This library is distributed in the hope that it will be useful,
  8. but WITHOUT ANY WARRANTY; without even the implied warranty of
  9. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  10. Library General Public License for more details.
  11. You should have received a copy of the GNU Library General Public
  12. License along with this library; if not, write to the Free
  13. Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  14. */
  15. #include "cssysdef.h"
  16. #include "demo.h"
  17. #include "demoseq.h"
  18. #include "demoop.h"
  19. #include "demoldr.h"
  20. #include "ivideo/graph3d.h"
  21. #include "ivideo/graph2d.h"
  22. #include "ivideo/txtmgr.h"
  23. #include "ivaria/conout.h"
  24. #include "ivaria/view.h"
  25. #include "iengine/engine.h"
  26. #include "iengine/sector.h"
  27. #include "iengine/light.h"
  28. #include "iengine/camera.h"
  29. #include "iengine/mesh.h"
  30. #include "iengine/movable.h"
  31. #include "imesh/thing/polygon.h"
  32. #include "imesh/thing/thing.h"
  33. #include "imesh/object.h"
  34. #include "imesh/particle.h"
  35. #include "ivaria/reporter.h"
  36. #include "iutil/eventh.h"
  37. #include "iutil/comp.h"
  38. #include "iutil/objreg.h"
  39. #include "csutil/cscolor.h"
  40. #include "csgeom/path.h"
  41. #include "cstool/csfxscr.h"
  42. #include "iutil/plugin.h"
  43. //-----------------------------------------------------------------------------
  44. Demo* DemoSequenceManager::demo;
  45. DemoSequenceManager* DemoSequenceManager::demoseq;
  46. DemoSequenceManager::DemoSequenceManager (Demo* demo)
  47. {
  48. DemoSequenceManager::demo = demo;
  49. demoseq = this;
  50. iObjectRegistry* object_reg = demo->object_reg;
  51. iPluginManager* plugin_mgr = CS_QUERY_REGISTRY (object_reg, iPluginManager);
  52. seqmgr = CS_LOAD_PLUGIN (plugin_mgr, "crystalspace.utilities.sequence",
  53. iSequenceManager);
  54. plugin_mgr->DecRef ();
  55. if (!seqmgr)
  56. {
  57. demo->Report (CS_REPORTER_SEVERITY_ERROR,
  58. "Could not load sequence manager plugin!");
  59. exit (0);
  60. }
  61. do_fade = false;
  62. fade_value = 0;
  63. suspended = true;
  64. suspend_one_frame = false;
  65. main_sequence = NULL;
  66. }
  67. DemoSequenceManager::~DemoSequenceManager ()
  68. {
  69. Clear ();
  70. int i;
  71. for (i = 0 ; i < paths.Length () ; i++)
  72. {
  73. csNamedPath* np = (csNamedPath*)paths[i];
  74. delete np;
  75. }
  76. paths.DeleteAll ();
  77. if (seqmgr) seqmgr->DecRef ();
  78. if (main_sequence) main_sequence->DecRef ();
  79. }
  80. void DemoSequenceManager::Clear ()
  81. {
  82. seqmgr->Clear ();
  83. int i;
  84. for (i = 0 ; i < pathForMesh.Length () ; i++)
  85. {
  86. PathForMesh* pfm = (PathForMesh*)pathForMesh[i];
  87. delete pfm;
  88. }
  89. pathForMesh.DeleteAll ();
  90. for (i = 0 ; i < meshRotation.Length () ; i++)
  91. {
  92. MeshRotation* mrot = (MeshRotation*)meshRotation[i];
  93. if (mrot->particle) mrot->particle->DecRef ();
  94. delete mrot;
  95. }
  96. meshRotation.DeleteAll ();
  97. }
  98. void DemoSequenceManager::Setup (const char* sequenceFileName)
  99. {
  100. if (main_sequence) main_sequence->DecRef ();
  101. DemoSequenceLoader* loader = new DemoSequenceLoader (
  102. DemoSequenceManager::demo, this, seqmgr, sequenceFileName);
  103. main_sequence = loader->GetSequence ("main");
  104. main_sequence->IncRef ();
  105. seqmgr->RunSequence (0, main_sequence);
  106. seqmgr->Resume ();
  107. suspended = false;
  108. main_start_time = seqmgr->GetMainTime ();
  109. num_frames = 0;
  110. delete loader;
  111. }
  112. void DemoSequenceManager::Suspend ()
  113. {
  114. if (!suspended)
  115. {
  116. suspended = true;
  117. seqmgr->Suspend ();
  118. }
  119. }
  120. void DemoSequenceManager::Resume ()
  121. {
  122. if (suspended)
  123. {
  124. suspended = false;
  125. seqmgr->Resume ();
  126. }
  127. }
  128. void DemoSequenceManager::Restart (const char* sequenceFileName)
  129. {
  130. Clear ();
  131. int i;
  132. for (i = 0 ; i < paths.Length () ; i++)
  133. {
  134. csNamedPath* np = (csNamedPath*)paths[i];
  135. delete np;
  136. }
  137. paths.DeleteAll ();
  138. if (main_sequence) { main_sequence->DecRef (); main_sequence = NULL; }
  139. do_fade = false;
  140. fade_value = 0;
  141. suspended = true;
  142. suspend_one_frame = false;
  143. Setup (sequenceFileName);
  144. }
  145. void DemoSequenceManager::TimeWarp (csTicks dt, bool restart)
  146. {
  147. // Temporarily resume everything to make sure our data is ok.
  148. bool sus = suspended;
  149. Resume ();
  150. // If we were suspended we say to the sequence manager to
  151. // suspend after one frame again. But we will have to go on
  152. // one frame to update the screen.
  153. if (sus) suspend_one_frame = true;
  154. if (seqmgr->GetMainTime () + dt <= main_start_time)
  155. {
  156. Clear ();
  157. seqmgr->RunSequence (0, main_sequence);
  158. main_start_time = seqmgr->GetMainTime ();
  159. num_frames = 0;
  160. return;
  161. }
  162. if (restart)
  163. {
  164. dt = seqmgr->GetMainTime () + dt - main_start_time;
  165. Clear ();
  166. seqmgr->RunSequence (0, main_sequence);
  167. main_start_time = seqmgr->GetMainTime ();
  168. num_frames = 0;
  169. seqmgr->TimeWarp (dt, false);
  170. return;
  171. }
  172. seqmgr->TimeWarp (dt, false);
  173. if (seqmgr->IsEmpty ())
  174. {
  175. // If the sequence manager is empty we insert the main sequence
  176. // again.
  177. seqmgr->RunSequence (0, main_sequence);
  178. }
  179. }
  180. void DemoSequenceManager::Draw3DEffects (iGraphics3D* g3d)
  181. {
  182. num_frames++;
  183. csTicks current_time = seqmgr->GetMainTime ();
  184. if (!suspended)
  185. {
  186. if (do_fade)
  187. {
  188. float r = float (current_time - start_fade_time)
  189. / float (total_fade_time);
  190. if (r >= 1)
  191. {
  192. r = 1;
  193. do_fade = false;
  194. }
  195. fade_value = start_fade * (1-r) + end_fade * r;
  196. if (fade_value < 0) fade_value = 0;
  197. if (fade_value > 1) fade_value = 1;
  198. }
  199. }
  200. if (fade_value > .001) csfxFadeOut (g3d, fade_value);
  201. }
  202. void DemoSequenceManager::Draw2DEffects (iGraphics2D* /*g2d*/)
  203. {
  204. }
  205. void DemoSequenceManager::SetupFade (float start_fade, float end_fade,
  206. csTicks total_fade_time, csTicks already_elapsed)
  207. {
  208. DemoSequenceManager::start_fade = start_fade;
  209. DemoSequenceManager::end_fade = end_fade;
  210. DemoSequenceManager::total_fade_time = total_fade_time;
  211. start_fade_time = seqmgr->GetMainTime ()-already_elapsed;
  212. if (already_elapsed >= total_fade_time)
  213. {
  214. // The fading is already done so we just set the fade
  215. // result to the final value.
  216. fade_value = end_fade;
  217. do_fade = false;
  218. }
  219. else
  220. {
  221. do_fade = true;
  222. }
  223. }
  224. void DemoSequenceManager::ReplacePathObject (csNamedPath* path,
  225. iMeshWrapper* mesh)
  226. {
  227. int i;
  228. for (i = 0 ; i < pathForMesh.Length () ; i++)
  229. {
  230. PathForMesh* pfm = (PathForMesh*)pathForMesh[i];
  231. if (pfm->path == path)
  232. {
  233. pfm->mesh = mesh;
  234. return;
  235. }
  236. }
  237. }
  238. void DemoSequenceManager::SetupPath (csNamedPath* path,
  239. iMeshWrapper* mesh,
  240. csTicks total_path_time,
  241. csTicks already_elapsed)
  242. {
  243. PathForMesh* pfm = new PathForMesh ();
  244. pfm->path = path;
  245. pfm->mesh = mesh;
  246. pfm->total_path_time = total_path_time;
  247. pfm->start_path_time = seqmgr->GetMainTime ()-already_elapsed;
  248. pathForMesh.Push (pfm);
  249. }
  250. void DemoSequenceManager::ControlPaths (iCamera* camera, csTicks elapsed_time)
  251. {
  252. if (suspended) return;
  253. csTicks current_time = seqmgr->GetMainTime ();
  254. int i = 0;
  255. int len = pathForMesh.Length ();
  256. while (i < len)
  257. {
  258. PathForMesh* pfm = (PathForMesh*)pathForMesh[i];
  259. float r = float (current_time - pfm->start_path_time)
  260. / float (pfm->total_path_time);
  261. bool do_path = true;
  262. if (r >= 1)
  263. {
  264. r = 1;
  265. do_path = false;
  266. }
  267. pfm->path->Calculate (r);
  268. csVector3 pos, up, forward;
  269. pfm->path->GetInterpolatedPosition (pos);
  270. pfm->path->GetInterpolatedUp (up);
  271. pfm->path->GetInterpolatedForward (forward);
  272. if (pfm->mesh)
  273. {
  274. iMovable* movable = pfm->mesh->GetMovable ();
  275. movable->SetPosition (pos);
  276. movable->GetTransform ().LookAt (forward.Unit (), up.Unit ());
  277. movable->UpdateMove ();
  278. pfm->mesh->DeferUpdateLighting (CS_NLIGHT_STATIC|CS_NLIGHT_DYNAMIC, 10);
  279. }
  280. else
  281. {
  282. camera->GetTransform ().SetOrigin (pos);
  283. camera->GetTransform ().LookAt (forward.Unit (), up.Unit ());
  284. }
  285. if (!do_path)
  286. {
  287. delete pfm;
  288. pathForMesh.Delete (i);
  289. len--;
  290. }
  291. else i++;
  292. }
  293. i = 0;
  294. len = meshRotation.Length ();
  295. while (i < len)
  296. {
  297. MeshRotation* mrot = (MeshRotation*)meshRotation[i];
  298. if (current_time > mrot->start_time + mrot->total_time)
  299. {
  300. if (mrot->particle) mrot->particle->DecRef ();
  301. delete mrot;
  302. meshRotation.Delete (i);
  303. len--;
  304. }
  305. else
  306. {
  307. mrot->particle->Rotate (mrot->angle_speed * float (elapsed_time/1000.));
  308. i++;
  309. }
  310. }
  311. if (suspend_one_frame) { Suspend (); suspend_one_frame = false; }
  312. }
  313. void DemoSequenceManager::DebugPositionObjects (iCamera* camera,
  314. csTicks debug_time)
  315. {
  316. int i = 0;
  317. int len = pathForMesh.Length ();
  318. while (i < len)
  319. {
  320. PathForMesh* pfm = (PathForMesh*)pathForMesh[i];
  321. float r = float (debug_time - pfm->start_path_time)
  322. / float (pfm->total_path_time);
  323. if (r >= 0 && r <= 1)
  324. {
  325. pfm->path->Calculate (r);
  326. csVector3 pos, up, forward;
  327. pfm->path->GetInterpolatedPosition (pos);
  328. pfm->path->GetInterpolatedUp (up);
  329. pfm->path->GetInterpolatedForward (forward);
  330. if (pfm->mesh)
  331. {
  332. iMovable* movable = pfm->mesh->GetMovable ();
  333. movable->SetPosition (pos);
  334. movable->GetTransform ().LookAt (forward.Unit (), up.Unit ());
  335. movable->UpdateMove ();
  336. pfm->mesh->DeferUpdateLighting (CS_NLIGHT_STATIC|CS_NLIGHT_DYNAMIC, 10);
  337. }
  338. else
  339. {
  340. camera->GetTransform ().SetOrigin (pos);
  341. camera->GetTransform ().LookAt (forward.Unit (), up.Unit ());
  342. }
  343. }
  344. i++;
  345. }
  346. }
  347. void DemoSequenceManager::DebugDrawPath (csNamedPath* np, bool hi,
  348. const csVector2& tl, const csVector2& br, int selpoint)
  349. {
  350. int dim = demo->myG2D->GetHeight ()-10;
  351. int col = demo->col_gray;
  352. if (hi) col = demo->col_white;
  353. float r;
  354. csVector3 p;
  355. for (r = 0 ; r <= 1 ; r += .001)
  356. {
  357. np->Calculate (r);
  358. np->GetInterpolatedPosition (p);
  359. int x = int ((p.x-tl.x)*dim / (br.x-tl.x));
  360. int y = int ((p.z-tl.y)*dim / (br.y-tl.y));
  361. if (x > 0 && x < dim && y > 0 && y < dim)
  362. demo->myG2D->DrawPixel (x, y, col);
  363. }
  364. float* px, * py, * pz;
  365. px = np->GetDimensionValues (0);
  366. py = np->GetDimensionValues (1);
  367. pz = np->GetDimensionValues (2);
  368. float* fx, * fy, * fz;
  369. fx = np->GetDimensionValues (6);
  370. fy = np->GetDimensionValues (7);
  371. fz = np->GetDimensionValues (8);
  372. int j;
  373. for (j = 0 ; j < np->GetPointCount () ; j++)
  374. {
  375. int col = demo->col_red;
  376. if (hi && selpoint == j) col = demo->col_green;
  377. int x = int ((px[j]-tl.x)*dim/(br.x-tl.x));
  378. int y = int ((pz[j]-tl.y)*dim/(br.y-tl.y));
  379. if (x > 0 && x < dim && y > 0 && y < dim)
  380. {
  381. demo->myG2D->DrawPixel (x, y, col);
  382. demo->myG2D->DrawPixel (x-1, y, col);
  383. demo->myG2D->DrawPixel (x+1, y, col);
  384. demo->myG2D->DrawPixel (x, y-1, col);
  385. demo->myG2D->DrawPixel (x, y+1, col);
  386. if (hi && selpoint == j)
  387. {
  388. csVector3 forward (fx[j], fy[j], fz[j]);
  389. forward.Normalize ();
  390. forward *= 20.;
  391. demo->myG2D->DrawLine (x, y, int (x+forward.x), int (y-forward.z),
  392. demo->col_cyan);
  393. }
  394. }
  395. }
  396. }
  397. void DemoSequenceManager::DrawSelPoint (
  398. const csVector3& pos, const csVector3& forward,
  399. const csVector2& tl, const csVector2& br,
  400. int dim, int col, float fwlen)
  401. {
  402. int x = int ((pos.x-tl.x)*dim/(br.x-tl.x));
  403. int y = int ((pos.z-tl.y)*dim/(br.y-tl.y));
  404. if (x > 0 && x < dim && y > 0 && y < dim)
  405. {
  406. demo->myG2D->DrawPixel (x, y, col);
  407. demo->myG2D->DrawPixel (x-1, y-1, col);
  408. demo->myG2D->DrawPixel (x-2, y-2, col);
  409. demo->myG2D->DrawPixel (x+1, y+1, col);
  410. demo->myG2D->DrawPixel (x+2, y+2, col);
  411. demo->myG2D->DrawPixel (x+1, y-1, col);
  412. demo->myG2D->DrawPixel (x+2, y-2, col);
  413. demo->myG2D->DrawPixel (x-1, y+1, col);
  414. demo->myG2D->DrawPixel (x-2, y+2, col);
  415. csVector3 f = forward;
  416. f.Normalize ();
  417. f *= fwlen;
  418. demo->myG2D->DrawLine (x, y, int (x+f.x), int (y-f.z), col);
  419. }
  420. }
  421. void DemoSequenceManager::DebugDrawPaths (iCamera* camera,
  422. const char* hilight, const csVector2& tl, const csVector2& br,
  423. int selpoint)
  424. {
  425. int i;
  426. int len = pathForMesh.Length ();
  427. csTicks current_time = seqmgr->GetMainTime ();
  428. //=====
  429. // Draw the border around the map.
  430. //=====
  431. int dim = demo->myG2D->GetHeight ()-10;
  432. demo->myG2D->DrawLine (0, 0, dim, 0, demo->col_cyan);
  433. demo->myG2D->DrawLine (0, dim, dim, dim, demo->col_cyan);
  434. demo->myG2D->DrawLine (0, 0, 0, dim, demo->col_cyan);
  435. demo->myG2D->DrawLine (dim, 0, dim, dim, demo->col_cyan);
  436. //=====
  437. // Draw the current camera.
  438. //=====
  439. csVector3 campos = camera->GetTransform ().GetOrigin ();
  440. csVector3 camfwd = camera->GetTransform ().This2Other (csVector3 (0, 0, 1)) -
  441. campos;
  442. DrawSelPoint (campos, camfwd, tl, br, dim, demo->col_green, 20);
  443. //=====
  444. // Get the current selected path.
  445. //=====
  446. csTicks start = 0, total = 0, seltime = 0;
  447. csNamedPath* selnp = NULL;
  448. if (hilight) selnp = GetSelectedPath (hilight, start, total);
  449. if (selnp)
  450. {
  451. // Calculate where we are in time on the selected path.
  452. float t = selnp->GetTimeValue (selpoint);
  453. seltime = csTicks (start + total*t);
  454. }
  455. //=====
  456. // Draw all active paths.
  457. //=====
  458. i = 0;
  459. while (i < len)
  460. {
  461. PathForMesh* pfm = (PathForMesh*)pathForMesh[i];
  462. bool hi = (pfm->path == selnp);
  463. DebugDrawPath (pfm->path, hi, tl, br, selpoint);
  464. i++;
  465. }
  466. //=====
  467. // Indicate the current camera point on all paths.
  468. // In addition also indicate points on the other paths
  469. // which correspond with the current selected point on the selected path.
  470. //=====
  471. i = 0;
  472. while (i < len)
  473. {
  474. PathForMesh* pfm = (PathForMesh*)pathForMesh[i];
  475. bool hi = (pfm->path == selnp);
  476. // Fetch the current time.
  477. csTicks ct = current_time;
  478. // Calculate where we are on this path at the moment.
  479. // r should be between 0 and 1.
  480. float r = float (ct - pfm->start_path_time)
  481. / float (pfm->total_path_time);
  482. if (r >= 1) r = 1;
  483. pfm->path->Calculate (r);
  484. // We are going to show both the position as the forward vector.
  485. csVector3 pos, forward;
  486. pfm->path->GetInterpolatedPosition (pos);
  487. pfm->path->GetInterpolatedForward (forward);
  488. DrawSelPoint (pos, forward, tl, br, dim, demo->col_yellow, 20);
  489. // If there is a hilighted path and we are not busy drawing the hilighted
  490. // path then we will draw an additional point on this path to indicate
  491. // where this path will be when the selected path is at the selected point.
  492. if (!hi && selnp)
  493. {
  494. r = float (seltime - pfm->start_path_time)
  495. / float (pfm->total_path_time);
  496. if (r >= 0 && r <= 1)
  497. {
  498. pfm->path->Calculate (r);
  499. pfm->path->GetInterpolatedPosition (pos);
  500. pfm->path->GetInterpolatedForward (forward);
  501. DrawSelPoint (pos, forward, tl, br, dim, demo->col_cyan, 10);
  502. }
  503. }
  504. i++;
  505. }
  506. }
  507. void DemoSequenceManager::SelectFirstPath (char* hilight)
  508. {
  509. if (pathForMesh.Length () > 0)
  510. {
  511. strcpy (hilight, ((PathForMesh*)pathForMesh[0])->path->GetName ());
  512. }
  513. }
  514. void DemoSequenceManager::SelectLastPath (char* hilight)
  515. {
  516. if (pathForMesh.Length () > 0)
  517. {
  518. strcpy (hilight, ((PathForMesh*)pathForMesh[
  519. pathForMesh.Length ()-1])->path->GetName ());
  520. }
  521. }
  522. void DemoSequenceManager::SelectPreviousPath (char* hilight)
  523. {
  524. csNamedPath* np = GetSelectedPath (hilight);
  525. if (!np)
  526. {
  527. SelectLastPath (hilight);
  528. return;
  529. }
  530. int i;
  531. for (i = 0 ; i < pathForMesh.Length () ; i++)
  532. {
  533. PathForMesh* pfm = (PathForMesh*)pathForMesh[i];
  534. if (pfm->path == np)
  535. {
  536. if (i == 0)
  537. return;
  538. else
  539. {
  540. pfm = (PathForMesh*)pathForMesh[i-1];
  541. strcpy (hilight, pfm->path->GetName ());
  542. }
  543. return;
  544. }
  545. }
  546. // We can't find the path. Switch back to last path.
  547. SelectLastPath (hilight);
  548. return;
  549. }
  550. void DemoSequenceManager::SelectNextPath (char* hilight)
  551. {
  552. csNamedPath* np = GetSelectedPath (hilight);
  553. if (!np)
  554. {
  555. SelectFirstPath (hilight);
  556. return;
  557. }
  558. int i;
  559. for (i = 0 ; i < pathForMesh.Length () ; i++)
  560. {
  561. PathForMesh* pfm = (PathForMesh*)pathForMesh[i];
  562. if (pfm->path == np)
  563. {
  564. if (i < pathForMesh.Length ()-1)
  565. {
  566. pfm = (PathForMesh*)pathForMesh[i+1];
  567. strcpy (hilight, pfm->path->GetName ());
  568. }
  569. return;
  570. }
  571. }
  572. // We can't find the path. Switch back to first path.
  573. SelectFirstPath (hilight);
  574. return;
  575. }
  576. csNamedPath* DemoSequenceManager::GetSelectedPath (const char* hilight)
  577. {
  578. csTicks s, t;
  579. return GetSelectedPath (hilight, s, t);
  580. }
  581. csNamedPath* DemoSequenceManager::GetSelectedPath (const char* hilight,
  582. csTicks& start, csTicks& total)
  583. {
  584. int i = 0;
  585. int len = pathForMesh.Length ();
  586. while (i < len)
  587. {
  588. PathForMesh* pfm = (PathForMesh*)pathForMesh[i];
  589. csNamedPath* np = pfm->path;
  590. bool hi = (hilight && !strcmp (np->GetName (), hilight));
  591. if (hi)
  592. {
  593. start = pfm->start_path_time;
  594. total = pfm->total_path_time;
  595. return np;
  596. }
  597. i++;
  598. }
  599. return NULL;
  600. }
  601. void DemoSequenceManager::SetupRotatePart (iMeshWrapper* mesh,
  602. float angle_speed, csTicks total_rotate_time, csTicks already_elapsed)
  603. {
  604. MeshRotation* mrot = new MeshRotation ();
  605. mrot->particle = SCF_QUERY_INTERFACE (mesh->GetMeshObject (), iParticle);
  606. if (!mrot->particle)
  607. {
  608. delete mrot;
  609. return;
  610. }
  611. mrot->mesh = mesh;
  612. mrot->total_time = total_rotate_time;
  613. mrot->start_time = seqmgr->GetMainTime ()-already_elapsed;
  614. mrot->angle_speed = angle_speed;
  615. meshRotation.Push (mrot);
  616. }
  617. float DemoSequenceManager::GetFPS ()
  618. {
  619. csTicks cur_time = seqmgr->GetMainTime ();
  620. csTicks dt = cur_time-main_start_time;
  621. return (float (num_frames) / float (dt)) * 1000.;
  622. }
  623. //-----------------------------------------------------------------------------