source: trunk/src/ticker.cpp @ 167

Last change on this file since 167 was 167, checked in by sam, 10 years ago

Store the frame number in the Ticker instead of duplicating the information
in each class that uses it.

  • 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 "core.h"
15
16/*
17 * Ticker implementation class
18 */
19
20static class TickerData
21{
22    friend class Ticker;
23
24public:
25    TickerData() :
26        todo(0), nentities(0),
27        frame(0), deltams(0), bias(0)
28    {
29        for (int i = 0; i < Entity::GROUP_COUNT; i++)
30            list[i] = NULL;
31    }
32
33    ~TickerData()
34    {
35#if !FINAL_RELEASE
36        if (nentities)
37            fprintf(stderr, "ERROR: still %i entities in ticker\n", nentities);
38#endif
39    }
40
41private:
42    /* Entity management */
43    Entity *todo;
44    Entity *list[Entity::GROUP_COUNT];
45    int nentities;
46
47    /* Fixed framerate management */
48    int frame;
49    Timer timer;
50    float deltams, bias;
51}
52tickerdata;
53
54static TickerData * const data = &tickerdata;
55
56/*
57 * Ticker public class
58 */
59
60void Ticker::Register(Entity *entity)
61{
62    /* If we are called from its constructor, the object's vtable is not
63     * ready yet, so we do not know which group this entity belongs to. Wait
64     * until the first tick. */
65    entity->next = data->todo;
66    data->todo = entity;
67}
68
69void Ticker::TickGame()
70{
71    Profiler::Stop(Profiler::STAT_TICK_FRAME);
72    Profiler::Start(Profiler::STAT_TICK_FRAME);
73
74    Profiler::Start(Profiler::STAT_TICK_GAME);
75
76    data->frame++;
77
78    data->deltams = data->timer.GetMs();
79    data->bias += data->deltams;
80
81    /* Garbage collect objects that can be destroyed. We can do this
82     * before inserting awaiting objects, because there is no way these
83     * are already marked for destruction. */
84    for (int i = 0; i < Entity::GROUP_COUNT; i++)
85        for (Entity *e = data->list[i], *prev = NULL; e; prev = e, e = e->next)
86            if (e->destroy)
87            {
88                if (prev)
89                    prev->next = e->next;
90                else
91                    data->list[i] = e->next;
92
93                data->nentities--;
94                delete e;
95            }
96
97    /* Insert waiting objects into the appropriate lists */
98    while (data->todo)
99    {
100        Entity *e = data->todo;
101        data->todo = e->next;
102
103        int i = e->GetGroup();
104        e->next = data->list[i];
105        data->list[i] = e;
106        data->nentities++;
107    }
108
109    /* Tick objects for the game loop */
110    for (int i = 0; i < Entity::GROUP_COUNT; i++)
111        for (Entity *e = data->list[i]; e; e = e->next)
112            if (!e->destroy)
113            {
114#if !FINAL_RELEASE
115                if (e->state != Entity::STATE_IDLE)
116                    fprintf(stderr, "ERROR: entity not idle for game tick\n");
117                e->state = Entity::STATE_PRETICK_GAME;
118#endif
119                e->TickGame(data->deltams);
120#if !FINAL_RELEASE
121                if (e->state != Entity::STATE_POSTTICK_GAME)
122                    fprintf(stderr, "ERROR: entity missed super game tick\n");
123                e->state = Entity::STATE_IDLE;
124#endif
125            }
126
127    Profiler::Stop(Profiler::STAT_TICK_GAME);
128}
129
130void Ticker::TickDraw()
131{
132    Profiler::Start(Profiler::STAT_TICK_DRAW);
133
134    /* Tick objects for the draw loop */
135    for (int i = 0; i < Entity::GROUP_COUNT; i++)
136        for (Entity *e = data->list[i]; e; e = e->next)
137            if (!e->destroy)
138            {
139#if !FINAL_RELEASE
140                if (e->state != Entity::STATE_IDLE)
141                    fprintf(stderr, "ERROR: entity not idle for draw tick\n");
142                e->state = Entity::STATE_PRETICK_DRAW;
143#endif
144                e->TickDraw(data->deltams);
145#if !FINAL_RELEASE
146                if (e->state != Entity::STATE_POSTTICK_DRAW)
147                    fprintf(stderr, "ERROR: entity missed super draw tick\n");
148                e->state = Entity::STATE_IDLE;
149#endif
150            }
151
152    Profiler::Stop(Profiler::STAT_TICK_DRAW);
153    Profiler::Start(Profiler::STAT_TICK_BLIT);
154}
155
156void Ticker::ClampFps(float deltams)
157{
158    Profiler::Stop(Profiler::STAT_TICK_BLIT);
159
160    if (deltams > data->bias + 200.0f)
161        deltams = data->bias + 200.0f; // Don't go below 5 fps
162    if (deltams > data->bias)
163        data->timer.WaitMs(deltams - data->bias);
164    data->bias -= deltams;
165}
166
167int Ticker::GetFrameNum()
168{
169    return data->frame;
170}
171
Note: See TracBrowser for help on using the repository browser.