Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

source: code/branches/core2/src/orxonox/tools/Timer.h @ 2258

Last change on this file since 2258 was 1001, checked in by landauf, 17 years ago

ok, be aware, here comes a big one. people with weak nerves should probably better look away or take some serious drugs.
this update includes partial and explicit class template specialization, partial and explicit specialized template function overloading, template meta programming and a simple typecast.
yeah right, a typecast. but let me explain the whole story from the beginning.

it all started with a simple problem: i had a double in a MultiType and wanted a float, but i always got 0. what was the problem? the conversion 'MultiType to anyting' was handled by the Converter class in util/Convert.h and the Converter was specialized for strings, multitypes, vectors and so on, but not for int, float, bool, …
so i've first wanted to implement a typecast as default, but this was a bad idea because it doesn't work for almost every generic type.
implementing an explicit specialization for every possible pair of primitives (did you ever happened to use an unsigned short? or a long double? no? ignorants :D) would have been a simple but ugly solution.
but there were other problems: if there's a rule to convert a string into anything and another rule to convert anything into an int - what happens if you want to convert a string into an int? compiler error! …ambiguous partial template specialization.
so i've spent days and nights to find a solution. this is my 5th try or so and i'm still really unsure if it works, but it's the first version i want to commit to have at least a backup.
if you're interested in looking at the code you better wait until i've cleaned up the whole thing, it's a real mess. and i want to do further tests, but now i'm tired. good night ;)

File size: 9.3 KB
Line 
1/*
2 *   ORXONOX - the hottest 3D action shooter ever to exist
3 *
4 *
5 *   License notice:
6 *
7 *   This program is free software; you can redistribute it and/or
8 *   modify it under the terms of the GNU General Public License
9 *   as published by the Free Software Foundation; either version 2
10 *   of the License, or (at your option) any later version.
11 *
12 *   This program is distributed in the hope that it will be useful,
13 *   but WITHOUT ANY WARRANTY; without even the implied warranty of
14 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15 *   GNU General Public License for more details.
16 *
17 *   You should have received a copy of the GNU General Public License
18 *   along with this program; if not, write to the Free Software
19 *   Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
20 *
21 *   Author:
22 *      Fabian 'x3n' Landau
23 *   Co-authors:
24 *      ...
25 *
26 */
27
28/*!
29    @file Timer.h
30    @brief Definition and Implementation of the Timer class.
31
32    The Timer is a callback-object, calling a given function after a given time-interval.
33
34    Usage:
35    header.h:
36        class ClassName
37        {
38            public:
39                ClassName();
40                void functionName();
41                Timer<ClassName> myTimer;
42        };
43
44    source.cc:
45        include "core/Executor.h"
46
47        ClassName::ClassName()
48        {
49            myTimer.setTimer(interval_in_seconds, bLoop, this, createExecutor(createFunctor(&ClassName::functionName)));
50        }
51
52        void ClassName::functionName()
53        {
54            whateveryouwant();
55            something(else);
56        }
57*/
58
59#ifndef _Timer_H__
60#define _Timer_H__
61
62#include <OgreFrameListener.h>
63#include "OrxonoxPrereqs.h"
64#include "core/CorePrereqs.h"
65#include "../objects/Tickable.h"
66
67namespace orxonox
68{
69    class StaticTimer;
70    void delay(float delay, const std::string& command);
71    void executeDelayedCommand(StaticTimer* timer, const std::string& command);
72
73    //! TimerBase is the parent of the Timer class.
74    class _OrxonoxExport TimerBase : public OrxonoxClass
75    {
76        friend class TimerFrameListener;
77
78        public:
79            ~TimerBase();
80
81            void run() const;
82
83            /** @brief Starts the Timer: Function-call after 'interval' seconds. */
84            inline void startTimer()
85                { this->bActive_ = true; this->time_ = this->interval_; }
86            /** @brief Stops the Timer. */
87            inline void stopTimer()
88                { this->bActive_ = false; this->time_ = this->interval_; }
89            /** @brief Pauses the Timer - it will continue with the actual state if you unpause it. */
90            inline void pauseTimer()
91                { this->bActive_ = false; }
92            /** @brief Unpauses the Timer - continues with the given state. */
93            inline void unpauseTimer()
94                { this->bActive_ = true; }
95            /** @brief Returns true if the Timer is active (= not stoped, not paused). @return True = Time is active */
96            inline bool isActive() const
97                { return this->bActive_; }
98            /** @brief Gives the Timer some extra time. @param time The amount of extra time in seconds */
99            inline void addTime(float time)
100                { this->time_ += time; }
101            /** @brief Decreases the remaining time of the Timer. @param time The amount of time to remove */
102            inline void removeTime(float time)
103                { this->time_ -= time; }
104            /** @brief Sets the interval of the Timer. @param interval The interval */
105            inline void setInterval(float interval)
106                { this->interval_ = interval; }
107            /** @brief Sets bLoop to a given value. @param bLoop True = loop */
108            inline void setLoop(bool bLoop)
109                { this->bLoop_ = bLoop; }
110
111        protected:
112            TimerBase();
113
114            Executor* executor_; //!< The executor of the function that should be called when the time expires
115
116            float interval_;     //!< The time-interval in seconds
117            bool bLoop_;         //!< If true, the function gets called every 'interval' seconds
118            bool bActive_;       //!< If true, the Timer ticks and calls the function if the time's up
119
120            float time_;         //!< Internal variable, counting the time till the next function-call
121    };
122
123    //! The Timer is a callback-object, calling a given function after a given time-interval.
124    template <class T = BaseObject>
125    class Timer : public TimerBase
126    {
127        public:
128            Timer() {}
129
130            /**
131                @brief Constructor: Initializes the Timer with given values.
132                @param interval The timer-interval in seconds
133                @param bLoop If true, the function gets called every 'interval' seconds
134                @param object The object owning the timer and the function
135                @param exeuctor A executor of the function to call
136            */
137            Timer(float interval, bool bLoop, T* object, ExecutorMember<T>* exeuctor)
138            {
139                this->setTimer(interval, bLoop, object, exeuctor);
140            }
141
142            /**
143                @brief Initializes the Timer with given values.
144                @param interval The timer-interval in seconds
145                @param bLoop If true, the function gets called every 'interval' seconds
146                @param object The object owning the timer and the function
147                @param exeuctor A executor of the function to call
148            */
149            void setTimer(float interval, bool bLoop, T* object, ExecutorMember<T>* executor)
150            {
151                this->interval_ = interval;
152                this->bLoop_ = bLoop;
153                executor->setObject(object);
154                this->executor_ = (Executor*)executor;
155                this->bActive_ = true;
156
157                this->time_ = interval;
158            }
159    };
160
161    //! The StaticTimer is a callback-object, calling a static function after a given time-interval.
162    class StaticTimer : public TimerBase
163    {
164        public:
165            StaticTimer() {}
166
167            /**
168                @brief Constructor: Initializes the Timer with given values.
169                @param interval The timer-interval in seconds
170                @param bLoop If true, the function gets called every 'interval' seconds
171                @param exeuctor A executor of the function to call
172            */
173            StaticTimer(float interval, bool bLoop, ExecutorStatic* executor)
174            {
175                this->setTimer(interval, bLoop, executor);
176            }
177
178            /**
179                @brief Initializes the Timer with given values.
180                @param interval The timer-interval in seconds
181                @param bLoop If true, the function gets called every 'interval' seconds
182                @param object The object owning the timer and the function
183                @param executor A executor of the function to call
184            */
185            void setTimer(float interval, bool bLoop, ExecutorStatic* executor)
186            {
187                this->interval_ = interval;
188                this->bLoop_ = bLoop;
189                this->executor_ = (Executor*)executor;
190                this->bActive_ = true;
191
192                this->time_ = interval;
193            }
194    };
195
196    //! The TimerFrameListener manages all Timers in the game.
197    class TimerFrameListener : public Ogre::FrameListener
198    {
199        private:
200            /** @brief Gets called before a frame gets rendered. */
201            bool frameStarted(const Ogre::FrameEvent &evt)
202            {
203                float dt = evt.timeSinceLastFrame * getTimeFactor();
204                // Iterate through all Timers
205                for (Iterator<TimerBase> it = ObjectList<TimerBase>::start(); it; )
206                {
207                    if (it->isActive())
208                    {
209                        // If active: Decrease the timer by the duration of the last frame
210                        it->time_ -= dt;
211
212                        if (it->time_ <= 0)
213                        {
214                            // It's time to call the function
215                            if (it->bLoop_)
216                            {
217                                it->time_ += it->interval_; // Q: Why '+=' and not '='? A: Think about it. It's more accurate like that. Seriously.
218                                while (it->time_ <= 0)
219                                {
220                                    // The interval was shorter than one tick, so execute the function more than once
221                                    it->run();
222                                    it->time_ += it->interval_;
223                                }
224                            }
225                            else
226                                it->stopTimer(); // Stop the timer if we don't want to loop
227
228                            (it++)->run();
229                        }
230                        else
231                            ++it;
232                    }
233                    else
234                        ++it;
235                }
236
237                return FrameListener::frameStarted(evt);
238            }
239    };
240}
241
242#endif /* _Timer_H__ */
Note: See TracBrowser for help on using the repository browser.