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