141 rivejä
3.1 KiB

  1. //
  2. // Deus Hax (working title)
  3. // Copyright (c) 2010 Sam Hocevar <sam@hocevar.net>
  4. //
  5. #if defined HAVE_CONFIG_H
  6. # include "config.h"
  7. #endif
  8. #include <cstdlib>
  9. #include <cstdio>
  10. #include <stdint.h>
  11. #include "profiler.h"
  12. #include "ticker.h"
  13. #include "asset.h"
  14. #include "timer.h"
  15. /*
  16. * Ticker implementation class
  17. */
  18. static class TickerData
  19. {
  20. friend class Ticker;
  21. public:
  22. TickerData() :
  23. todo(0),
  24. nassets(0)
  25. {
  26. for (int i = 0; i < Asset::GROUP_COUNT; i++)
  27. list[i] = NULL;
  28. bias = 0.0f;
  29. }
  30. ~TickerData()
  31. {
  32. #if !FINAL_RELEASE
  33. if (nassets)
  34. fprintf(stderr, "ERROR: still %i assets in ticker\n", nassets);
  35. #endif
  36. }
  37. private:
  38. /* Asset management */
  39. Asset *todo;
  40. Asset *list[Asset::GROUP_COUNT];
  41. int nassets;
  42. /* Fixed framerate management */
  43. Timer timer;
  44. float delta_time, bias;
  45. }
  46. tickerdata;
  47. static TickerData * const data = &tickerdata;
  48. /*
  49. * Ticker public class
  50. */
  51. void Ticker::Register(Asset *asset)
  52. {
  53. /* If we are called from its constructor, the object's vtable is not
  54. * ready yet, so we do not know which group this asset belongs to. Wait
  55. * until the first tick. */
  56. asset->next = data->todo;
  57. data->todo = asset;
  58. }
  59. void Ticker::TickGame()
  60. {
  61. Profiler::Stop(Profiler::STAT_TICK_FRAME);
  62. Profiler::Start(Profiler::STAT_TICK_FRAME);
  63. Profiler::Start(Profiler::STAT_TICK_GAME);
  64. data->delta_time = data->timer.GetSeconds();
  65. data->bias += data->delta_time;
  66. /* Insert waiting objects in the appropriate lists */
  67. while (data->todo)
  68. {
  69. Asset *a = data->todo;
  70. data->todo = a->next;
  71. int i = a->GetGroup();
  72. a->next = data->list[i];
  73. data->list[i] = a;
  74. data->nassets++;
  75. }
  76. /* Garbage collect objects that can be destroyed */
  77. for (int i = 0; i < Asset::GROUP_COUNT; i++)
  78. for (Asset *a = data->list[i], *prev = NULL; a; prev = a, a = a->next)
  79. if (a->destroy)
  80. {
  81. if (prev)
  82. prev->next = a->next;
  83. else
  84. data->list[i] = a->next;
  85. data->nassets--;
  86. delete a;
  87. }
  88. /* Tick objects for the game loop */
  89. for (int i = 0; i < Asset::GROUP_COUNT; i++)
  90. for (Asset *a = data->list[i]; a; a = a->next)
  91. if (!a->destroy)
  92. a->TickGame(data->delta_time);
  93. Profiler::Stop(Profiler::STAT_TICK_GAME);
  94. }
  95. void Ticker::TickRender()
  96. {
  97. Profiler::Start(Profiler::STAT_TICK_RENDER);
  98. /* Tick objects for the render loop */
  99. for (int i = 0; i < Asset::GROUP_COUNT; i++)
  100. for (Asset *a = data->list[i]; a; a = a->next)
  101. if (!a->destroy)
  102. a->TickRender(data->delta_time);
  103. Profiler::Stop(Profiler::STAT_TICK_RENDER);
  104. Profiler::Start(Profiler::STAT_TICK_BLIT);
  105. }
  106. void Ticker::ClampFps(float fps)
  107. {
  108. Profiler::Stop(Profiler::STAT_TICK_BLIT);
  109. float ideal_time = 1.0f / fps;
  110. if (ideal_time > data->bias)
  111. data->timer.WaitSeconds(ideal_time - data->bias);
  112. data->bias -= ideal_time;
  113. }