source: trunk/src/ticker.cpp @ 130

Last change on this file since 130 was 130, checked in by sam, 11 years ago

Try to detect assets not calling their super tick methods. Already spotted
one bug thanks to that.

  • Property svn:keywords set to Id
File size: 4.2 KB
Line 
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
23static class TickerData
24{
25    friend class Ticker;
26
27public:
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
45private:
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}
55tickerdata;
56
57static TickerData * const data = &tickerdata;
58
59/*
60 * Ticker public class
61 */
62
63void 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
72void 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            {
115#if !FINAL_RELEASE
116                if (a->state != Asset::STATE_IDLE)
117                    fprintf(stderr, "ERROR: asset not idle for game tick\n");
118                a->state = Asset::STATE_PRETICK_GAME;
119#endif
120                a->TickGame(data->delta_time);
121#if !FINAL_RELEASE
122                if (a->state != Asset::STATE_POSTTICK_GAME)
123                    fprintf(stderr, "ERROR: asset missed super game tick\n");
124                a->state = Asset::STATE_IDLE;
125#endif
126            }
127
128    Profiler::Stop(Profiler::STAT_TICK_GAME);
129}
130
131void Ticker::TickRender()
132{
133    Profiler::Start(Profiler::STAT_TICK_RENDER);
134
135    /* Tick objects for the render loop */
136    for (int i = 0; i < Asset::GROUP_COUNT; i++)
137        for (Asset *a = data->list[i]; a; a = a->next)
138            if (!a->destroy)
139            {
140#if !FINAL_RELEASE
141                if (a->state != Asset::STATE_IDLE)
142                    fprintf(stderr, "ERROR: asset not idle for render tick\n");
143                a->state = Asset::STATE_PRETICK_RENDER;
144#endif
145                a->TickRender(data->delta_time);
146#if !FINAL_RELEASE
147                if (a->state != Asset::STATE_POSTTICK_RENDER)
148                    fprintf(stderr, "ERROR: asset missed super render tick\n");
149                a->state = Asset::STATE_IDLE;
150#endif
151            }
152
153    Profiler::Stop(Profiler::STAT_TICK_RENDER);
154    Profiler::Start(Profiler::STAT_TICK_BLIT);
155}
156
157void Ticker::ClampFps(float delta_time)
158{
159    Profiler::Stop(Profiler::STAT_TICK_BLIT);
160
161    if (delta_time > data->bias + 0.2f)
162        delta_time = data->bias + 0.2f; // Don't go below 5 fps
163    if (delta_time > data->bias)
164        data->timer.WaitSeconds(delta_time - data->bias);
165    data->bias -= delta_time;
166}
167
Note: See TracBrowser for help on using the repository browser.