Clock.h

00001 /***************************************************************************
00002  *                                                                         *
00003  *   (c) Art Tevs, MPI Informatik Saarbruecken                             *
00004  *       mailto: <tevs@mpi-sb.mpg.de>                                      *
00005  *                                                                         *
00006  *   This program is free software; you can redistribute it and/or modify  *
00007  *   it under the terms of the GNU General Public License as published by  *
00008  *   the Free Software Foundation; either version 2 of the License, or     *
00009  *   (at your option) any later version.                                   *
00010  *                                                                         *
00011  ***************************************************************************/
00012 
00013 
00014 #ifndef _NR_C_CLOCK_H_
00015 #define _NR_C_CLOCK_H_
00016 
00017 
00018 //----------------------------------------------------------------------------------
00019 // Includes
00020 //----------------------------------------------------------------------------------
00021 #include "Prerequisities.h"
00022 #include "TimeSource.h"
00023 #include "ITimeObserver.h"
00024 #include "Timer.h"
00025 #include "ITask.h"
00026 #include "TimeSourceVirtual.h"
00027 #include "ScriptEngine.h"
00028 
00029 namespace nrEngine{
00030 
00031         //! Global clock of the engine used to retrieve time or create timers
00032         /**
00033         * \par
00034         * Clock allows you to create timers from it. Clock is always ticks if any
00035         * time source is bounded. In contrast to Einstein's relativity theory we have
00036         * only one global clock. So your complete application has one time which runs
00037         * with the same speed. But to be able to use Einstein's theory you can create
00038         * timers from each clock, which allows you to use different time speeds.
00039         * Clock can also derive/create timers. But if you want to create the timer by
00040         * yourself you can do this.
00041         *
00042         * @note
00043         *               - Our clock works internal with 64Bit float64 values to stay precise.
00044         *                       Because using of float32 values is enough for every simulation you will get
00045         *                       32Bit float32 values as frame interval time.
00046         *               - If you compile the engine on 64Bit systems, so you can change this and use
00047         *                       64Bit doubles instead.
00048         *               - Each created timer dies when clock dies.
00049         *               - You can only destroy timers through the clock interface or it will be
00050         *                       deleted automaticly from the memory when clock is deleted
00051         *               - Deleting the timer outside from the clock has no effect
00052         *
00053         * \ingroup time
00054         **/
00055         class _NRExport Clock : public ITask {
00056         public:
00057         
00058                 /**
00059                 * Set the time source to be used to get current time. Our clock class
00060                 * is platform independent but the time get code depends mostly on the
00061                 * platform you using. So just derive your time source from ITimeSource
00062                 * interface and add this source into our clock.
00063                 * @param timeSource smart pointer containing to the time source
00064                 **/
00065                 void setTimeSource(SharedPtr<TimeSource> timeSource);
00066                 
00067                 /**
00068                 * Returns true if any time source is bounded to our clock.
00069                 **/
00070                 bool isAnySourceBounded();
00071                 
00072                 /**
00073                 * Return a smart pointer to the current time source
00074                 * @return a smart pointer pointing to the current time source or NULL if
00075                 * no time source is bound at now.
00076                 **/
00077                 SharedPtr<TimeSource> getTimeSource() { return timeSource; }
00078                 
00079                 /**
00080                  * This method will be called by the kernel to start the clock. It is called
00081                  * when clock is added to the kernel pipeline.
00082                  **/
00083                 Result onStartTask();
00084 
00085                 /**
00086                 * Updates the clock task by getting time values and calculating of
00087                 * frame rate and frame interval.
00088                 * Also each connected time observer will be notified so it can do
00089                 * own updates. This allows you just to create any observer (like timer)
00090                 * bind them to the clock and forgett it.
00091                 **/
00092                 Result updateTask();
00093 
00094                 /**
00095                 * Stop the clock task and release all used objects.
00096                 * So all observers will be deleted from the observer list and also
00097                 * the time source is removed. After this function you still able to access
00098                 * to the clock and timers (because of smart pointers), but the time will
00099                 * hold on and no updates of the time will be made.
00100                 **/
00101                 Result stopTask();
00102 
00103                 /**
00104                 * Same as taskUpdate(). This name is choosen to separate calls
00105                 * to the clock by not knowing, that it is a task.
00106                 * Use this function from somewhere else than a kernel.
00107                 **/
00108                 void            Ticks(){ updateTask();}
00109                 
00110                 /**
00111                 * Returns current time since clock start ticking.
00112                 **/
00113                 float64         getTime() const;
00114                 
00115         
00116                 /**
00117                 * Returns filtered interval time between two or more frames. nrEngine's clock
00118                 * does not only calculate the interval between two following frames, but it uses
00119                 * a arithmetic average to compute the frame interval between a lot of frames.
00120                 * This helps you to ignore some frames if their update time was to big or to less.
00121                 */
00122                 float32         getFrameInterval() const;
00123         
00124                 /**
00125                 * Returns number of frames drawn since clock start ticking
00126                 **/             
00127                 int32           getFrameNumber() const;
00128                         
00129                 /**
00130                 * Returns FPS. Like the frameinterval this value is also computed as average
00131                 * between a lot of frames. So this value is more smooth.
00132                 **/
00133                 float32         getFrameRate() const;
00134         
00135                 /**
00136                  * Get the frame interval time of a real time. If you use fix frame rate, so you
00137                  * get as an interval a 1.0 / fix frame rate. This method allows you to get
00138                  * the time which your frame really need to render.
00139                  **/
00140                 float32 getRealFrameInterval() const;
00141 
00142                 /**
00143                  * Get real frame rate based on getRealFrameInterval() method
00144                  **/
00145                 float32 getRealFrameRate() const;
00146 
00147                 /**
00148                  * This method allows you to set the maximal frame rate at which the clock
00149                  * shoudl run. It will use this frame rate as an upper bound. If applications
00150                  * runs faster than this time, so it will retard to this speed. If app runs
00151                  * much slower so nothing happens. At speed above the given boundaries
00152                  * the clock runs as for fixed frame rate. So you would retrieve fixed
00153                  * frame interval values. Function which retrieves real values are not
00154                  * affected by them, so you are still able to get information about the
00155                  * real time, which you frame need
00156                  **/
00157                 void setMaxFrameRate(bool set, float32 maxFPS = 60.0);
00158 
00159                 /**
00160                 * Add new time observer to our list of observers. Each observer will
00161                 * be notified on each frame after clock calculations are done. With this
00162                 * system we can separate our timers from game loop, but they still be
00163                 * updated on each frame.
00164                 * @param timeObserver smart pointers to the observer
00165                 * @return internal ID of observer to allow of removing them from the list
00166                 * @note Each observer has to implement the ITimeObserver interface
00167                 **/
00168                 int32           addObserver(SharedPtr<ITimeObserver> timeObserver);
00169                 
00170                 /**
00171                 * Removes an observer from the list by given ID
00172                 * @param observerID id of the observer returned by addObserver()
00173                 * @return either OK or:
00174                 *               - CLOCK_OBSERVER_NOT_FOUND if such id is not valid
00175                 **/
00176                 Result  removeObserver(int32 observerID);
00177                 
00178                 /**
00179                 * Add an time observer by a name. So you can delete them also by using
00180                 * this name.
00181                 * @param obsName name of the observer
00182                 * @param timeObserver smart pointer pointing to the observer
00183                 * @return either OK or:
00184                 *                       - CLOCK_OBSERVER_ALREADY_ADDED if such is already added
00185                 **/
00186                 Result  addObserver(const std::string& obsName, SharedPtr<ITimeObserver> timeObserver);
00187         
00188                 /**
00189                 * Removes an observer by using it's name.
00190                 * @param obsName name of the observer
00191                 * @return either OK or:
00192                 *                       - CLOCK_OBSERVER_NOT_FOUND if such an observer not exists
00193                 **/
00194                 Result  removeObserver(const std::string& obsName);
00195                 
00196                 /**
00197                 * Set the count of frames to be computed to calculate frame rate/interval.
00198                 * We need this to smooth big peaks on frame rates to allow application
00199                 * run smoother than without this window. Here we just using averaging
00200                 * of the frame intervals during certain number of frames.
00201                 * @param frameCount size of such frame calculation window
00202                 * @param defaultFrameTime is a frame interval added by default as if there
00203                 *               was a frame rendered with this speed. This allows us to start smoothly
00204                 **/
00205                 void    setFrameWindow(int32 frameCount = 10, float32 defaultFrameTime = 0.03333);
00206         
00207                 /**
00208                 * If you set this to true so fix frame rate will be used. This helps us
00209                 * to run our application on console or do internal calculations based
00210                 * on fix frame rate like Doom3 does.
00211                 * @param setFixRate if true fix frame rate will be used.
00212                 * @param fixFrameRate frame rate to be used
00213                 **/
00214                 void    setFixFrameRate(bool setFixRate, float32 fixFrameRate = 60.0f);
00215 
00216                 
00217                 /**
00218                 * Create a new timer which does use this clock as reference.
00219                 **/
00220                 SharedPtr<Timer>        createTimer();
00221 
00222                 /**
00223                 * Setup the syncing interval. The clock will be synced with system time
00224                 * so it helps to prevent timing errors produced by high performance time
00225                 * counters in addidition to CPU speed stepping functionality of the processor unit.
00226                 **/
00227                 void setSyncInterval(uint32 milliseconds);
00228                 
00229                 /**
00230                  * Reset the clock. The clock time will be resetted to the given time.
00231                  * @param resetToTime Reset the clock to the given time value
00232                  * @param resetAllObservers if true all registered obseervers would be also resetted
00233                  **/
00234                 void reset(float64 resetToTime = 0.0f, bool resetAllObservers = false);
00235                 
00236                 /**
00237                  * Script-Function to reset the clock. You can specify in parameters if all timers, which were
00238                  * created before should be also reseted.
00239                  **/
00240                 ScriptFunctionDef(scriptResetClock);
00241 
00242 
00243         private:
00244 
00245                 //! Only engine's core object can create instance
00246                 friend class Engine;
00247 
00248                 /**
00249                 * After the object is created and before it runs the returned value
00250                 * for the frame rate will be 0.
00251                 * The value for frame window is set to 7 per default.
00252                 **/
00253                 Clock();
00254 
00255                 /**
00256                 * Release all used memory.
00257                 **/
00258                 ~Clock();
00259 
00260                 // observers
00261                 typedef std::vector< SharedPtr<ITimeObserver> > ObserverList;
00262                 std::map < std::string, int32>  observerIDList;
00263                 ObserverList                            observers;
00264                 
00265                 // frame filtering
00266                 std::deque<float64>     frameDurationHistory;
00267                 float64                 frameDefaultTime;
00268                 int32                   frameFilteringWindow;
00269                 
00270                 // time source
00271                 SharedPtr<TimeSource>   timeSource;
00272                 SharedPtr<TimeSource>   realTimeSource;
00273                 float64         currentTime;
00274                 float64         frameTime;
00275                 int32           frameNumber;
00276                 bool            useFixRate;
00277                 float32         fixFrameRate;
00278 
00279                 float32     maxFrameRate;
00280                 float64     lastCurrentTime;
00281                 float64     invMaxFrameRate;
00282                 bool        useMaxRate;
00283 
00284                 // values to hold real frame information if we use fix frame rate
00285                 float64     realFrameTime;
00286 
00287                 // methods
00288                 void    _addToFrameHistory(float64 duration);
00289                 float64 _getFilteredFrameDuration() const;
00290                 float64 _getExactFrameDuration();
00291                 
00292                 // helping variables to find out the frame rate
00293                 float64 sourceStartValue;
00294                 float64 sourceLastValue;
00295                 float64 sourceLastRealValue;
00296                 
00297                 // Next time when the clock has to be synced with system time
00298                 float64 nextSyncTime;
00299                 uint32  syncInterval;
00300                 
00301         };
00302         
00303 }; // end namespace
00304 #endif

Generated on Wed Sep 12 23:19:42 2007 for nrEngine by  doxygen 1.5.1