File: timer.cpp

package info (click to toggle)
doomsday 1.10.4-2
  • links: PTS, VCS
  • area: main
  • in suites: jessie, jessie-kfreebsd
  • size: 36,784 kB
  • ctags: 51,834
  • sloc: ansic: 183,420; cpp: 157,702; python: 10,449; xml: 705; sh: 279; objc: 154; makefile: 143
file content (157 lines) | stat: -rw-r--r-- 3,679 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
/**
 * @file timer.cpp
 * Timing subsystem. @ingroup system
 *
 * @note Under WIN32, uses Win32 multimedia timing routines.
 *
 * @authors Copyright © 2003-2013 Jaakko Keränen <jaakko.keranen@iki.fi>
 * @authors Copyright © 2007-2013 Daniel Swanson <danij@dengine.net>
 * @authors Copyright © 2007-2008 Jamie Jones <jamie_jones_au@yahoo.com.au>
 *
 * @par License
 * GPL: http://www.gnu.org/licenses/gpl.html
 *
 * <small>This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by the
 * Free Software Foundation; either version 2 of the License, or (at your
 * option) any later version. This program is distributed in the hope that it
 * will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty
 * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
 * Public License for more details. You should have received a copy of the GNU
 * General Public License along with this program; if not, write to the Free
 * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
 * 02110-1301 USA</small>
 */

#include <QTime>

#ifdef WIN32
#  define WIN32_LEAN_AND_MEAN
#  include <windows.h>
#  include <mmsystem.h>
#endif

#include "de/timer.h"
#include "de/concurrency.h"

static float ticksPerSecond = TICSPERSEC;
static double timeOffset = 0;
static mutex_t timerMutex;         // To prevent Data races in the timer
static QTime startedAt;
static uint timerOffset = 0;

static uint const TIMER_WARP_INTERVAL = 12*60*60*1000;

void Timer_Shutdown(void)
{
#ifdef WIN32
    timeEndPeriod(1);
#endif
    mutex_t m = timerMutex;
    timerMutex = 0;
    Sys_DestroyMutex(m);
}

void Timer_Init(void)
{
    assert(timerMutex == 0);
    timerMutex = Sys_CreateMutex("TIMER_MUTEX");
#ifdef WIN32
    timeBeginPeriod(1);
#endif
    startedAt.start();
    timerOffset = 0;
}

unsigned int Timer_RealMilliseconds(void)
{
    static boolean first = true;
    static unsigned int start;
#ifdef WIN32
    DWORD return_time, now;
#else
    uint return_time, now;
#endif

    Sys_Lock(timerMutex);

#ifdef WIN32
    now = timeGetTime();
#else
    now = uint(startedAt.elapsed());
    if(now > TIMER_WARP_INTERVAL)
    {
        now += timerOffset;

        // QTime will wrap around every 24 hours; we'll wrap it manually before that.
        timerOffset += TIMER_WARP_INTERVAL;
        startedAt = startedAt.addMSecs(TIMER_WARP_INTERVAL);
    }
    else
    {
        now += timerOffset;
    }
#endif

    if(first)
    {
        first = false;
        start = now;

        Sys_Unlock(timerMutex);
        return 0;
    }

    // Wrapped around? (Every 50 days...)
    if(now < start)
    {
        return_time = 0xffffffff - start + now + 1;

        Sys_Unlock(timerMutex);
        return return_time;
    }

    return_time = now - start;

    Sys_Unlock(timerMutex);
    return return_time;
}

double Timer_Seconds(void)
{
    return (double) ((Timer_RealMilliseconds() / 1000.0) * (ticksPerSecond / 35)) + timeOffset;
}

double Timer_RealSeconds(void)
{
    return (double) (Timer_RealMilliseconds() / 1000.0);
}

double Timer_Ticksf(void)
{
    return Timer_Seconds() * 35;
}

int Timer_Ticks(void)
{
    return (int) Timer_Ticksf();
}

void Timer_SetTicksPerSecond(float newTics)
{
    double  nowTime = Timer_RealMilliseconds() / 1000.0;

    if(newTics <= 0)
        newTics = TICSPERSEC;

    // Update the time offset so that after the change time will
    // continue from the same value.
    timeOffset += nowTime * (ticksPerSecond - newTics) / 35;

    ticksPerSecond = newTics;
}

float Timer_TicksPerSecond(void)
{
    return ticksPerSecond;
}