source: trunk/src/ticker.cpp @ 147

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

Rename "asset" to "entity". It's way cooler.

  • 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 "entity.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        nentities(0)
31    {
32        for (int i = 0; i < Entity::GROUP_COUNT; i++)
33            list[i] = NULL;
34        bias = 0.0f;
35    }
36
37    ~TickerData()
38    {
39#if !FINAL_RELEASE
40        if (nentities)
41            fprintf(stderr, "ERROR: still %i entities in ticker\n", nentities);
42#endif
43    }
44
45private:
46    /* Entity management */
47    Entity *todo;
48    Entity *list[Entity::GROUP_COUNT];
49    int nentities;
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(Entity *entity)
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 entity belongs to. Wait
67     * until the first tick. */
68    entity->next = data->todo;
69    data->todo = entity;
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 < Entity::GROUP_COUNT; i++)
86        for (Entity *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->nentities--;
95                delete a;
96            }
97
98    /* Insert waiting objects into the appropriate lists */
99    while (data->todo)
100    {
101        Entity *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->nentities++;
108    }
109
110    /* Tick objects for the game loop */
111    for (int i = 0; i < Entity::GROUP_COUNT; i++)
112        for (Entity *a = data->list[i]; a; a = a->next)
113            if (!a->destroy)
114            {
115#if !FINAL_RELEASE
116                if (a->state != Entity::STATE_IDLE)
117                    fprintf(stderr, "ERROR: entity not idle for game tick\n");
118                a->state = Entity::STATE_PRETICK_GAME;
119#endif
120                a->TickGame(data->delta_time);
121#if !FINAL_RELEASE
122                if (a->state != Entity::STATE_POSTTICK_GAME)
123                    fprintf(stderr, "ERROR: entity missed super game tick\n");
124                a->state = Entity::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 < Entity::GROUP_COUNT; i++)
137        for (Entity *a = data->list[i]; a; a = a->next)
138            if (!a->destroy)
139            {
140#if !FINAL_RELEASE
141                if (a->state != Entity::STATE_IDLE)
142                    fprintf(stderr, "ERROR: entity not idle for render tick\n");
143                a->state = Entity::STATE_PRETICK_RENDER;
144#endif
145                a->TickRender(data->delta_time);
146#if !FINAL_RELEASE
147                if (a->state != Entity::STATE_POSTTICK_RENDER)
148                    fprintf(stderr, "ERROR: entity missed super render tick\n");
149                a->state = Entity::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.