| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196 |
- /******************************************************************************
- Flt Error for big values, obtained using the formula:
- Dbl sec=1, min=60*sec, hour=60*min, day=hour*24, month=day*30, year=month*12;
- Flt t=.., t1=t; IncRealByBit(t1); Flt dt=t1-t;
- 1 day : 0.0078125s
- 1 month: 0.25s
- 1 year : 2.0s
- 2 years: 4.0s
- 4 years: 8.0s
- 8 years: 16.0s
- /******************************************************************************
- Slow to Fast (1000000 calls)
- -clock (0.036s)
- -timeGetTime (0.018s)
- -GetTickCount (0.004s)
- -GetTickCount64 (0.004s)
- Precision:
- -clock ( 1ms)
- -timeGetTime ( 1ms)
- -GetTickCount (16ms)
- -GetTickCount64 (16ms)
- Measured with:
- Dbl t0[]={Time.curTime(), clock(), timeGetTime(), GetTickCount(), GetTickCount64()};
- REP(1000)
- {
- Dbl t1[]={Time.curTime(), clock(), timeGetTime(), GetTickCount(), GetTickCount64()};
- Dbl td[]={(t1[0]-t0[0])*1000, t1[1]-t0[1], t1[2]-t0[2], t1[3]-t0[3], t1[4]-t0[4]};
- LogName(S);
- LogConsole();
- LogN(S+td[0]+' '+td[1]+' '+td[2]+' '+td[3]+' '+td[4]);
- Copy(t0, t1);
- }
- /******************************************************************************/
- #include "stdafx.h"
- namespace EE{
- /******************************************************************************/
- TimeClass Time;
- /******************************************************************************/
- // TIME
- /******************************************************************************/
- TimeClass::TimeClass()
- {
- _pc=false;
- _skip=0;
- _start_time_ms=_frame=_frames_drawn=0;
- _start_time=0;
- _fps=_fps_time=_state_update=_state_draw=0;
- _rd_2=_rd_1=_rd=_ad=_d=_rt=_at=_st=_t=0;
- _time_mul=0;
- _speed=1;
- }
- /******************************************************************************/
- Dbl TimeClass::curTime()C
- {
- #if WINDOWS
- if(_pc)
- {
- LARGE_INTEGER pc; QueryPerformanceCounter(&pc);
- return (pc.QuadPart-_start_time)*_time_mul;
- }
- #if WINDOWS_OLD
- return (timeGetTime()-_start_time_ms)*_time_mul;
- #elif WINDOWS_NEW
- return (clock()-_start_time_ms)*_time_mul;
- #endif
- #elif APPLE
- return (mach_absolute_time()-_start_time)*_time_mul;
- #elif LINUX || ANDROID
- struct timespec time; clock_gettime(CLOCK_MONOTONIC, &time);
- return (ULong(time.tv_sec)*1000000000+time.tv_nsec-_start_time)/1000000000.;
- #elif WEB
- return (emscripten_get_now()-_start_time)/1000;
- #endif
- }
- UInt TimeClass::curTimeMs()C
- {
- #if WINDOWS_OLD
- return timeGetTime()-_start_time_ms;
- #elif WINDOWS_NEW
- return clock()-_start_time_ms; ASSERT(CLOCKS_PER_SEC==1000);
- #elif APPLE
- return TruncU((mach_absolute_time()-_start_time)*_time_mul*1000);
- #elif LINUX || ANDROID
- struct timespec time; clock_gettime(CLOCK_MONOTONIC, &time);
- return TruncU((ULong(time.tv_sec)*1000000000+time.tv_nsec-_start_time)*(1000/1000000000.));
- #elif WEB
- return TruncU(emscripten_get_now()-_start_time);
- #endif
- }
- /******************************************************************************/
- void TimeClass::speed(Flt speed)
- {
- if(T._speed!=speed)
- {
- T._speed=speed;
- SpeedSound();
- }
- }
- /******************************************************************************/
- void TimeClass::skipUpdate(Byte frames ) {MAX(_skip, frames);}
- void TimeClass::wait (Int milliseconds)
- {
- if(milliseconds>0)
- {
- #if WINDOWS
- Sleep(milliseconds);
- #else
- usleep(milliseconds*1000);
- #endif
- }
- }
- /******************************************************************************/
- void (*SteamSetTime)(); // have to use variable so we don't call 'Steam' manually (because that would force require DLL), but rather Steam methods set this pointer
- void TimeClass::create()
- {
- if(LogInit)LogN("TimeClass.create");
- #if WINDOWS
- LARGE_INTEGER value;
- if(_pc=(QueryPerformanceFrequency(&value)!=0))
- {
- _time_mul=1.0/value.QuadPart; // ticks per second
- QueryPerformanceCounter(&value); _start_time=value.QuadPart;
- }else
- {
- _time_mul=1.0/1000;
- }
- #if WINDOWS_OLD
- _start_time_ms=timeGetTime();
- #elif WINDOWS_NEW
- _start_time_ms=clock();
- #endif
- #elif APPLE
- mach_timebase_info_data_t info;
- mach_timebase_info(&info);
- _time_mul =info.numer/1000000000./info.denom; // use info and convert from nanoseconds to seconds
- _start_time=mach_absolute_time();
- #elif LINUX || ANDROID
- struct timespec time; clock_gettime(CLOCK_MONOTONIC, &time);
- _start_time=ULong(time.tv_sec)*1000000000+time.tv_nsec;
- #elif WEB
- _start_time=TruncUL(emscripten_get_now());
- #endif
- if(SteamSetTime)SteamSetTime();
- }
- /******************************************************************************/
- void TimeClass::update()
- {
- // this is no longer needed after adding 'new_rd' test below: if(!_rt)skipUpdate(); // if it's the first time we're updating the timer, then skip setting time delta's (if we won't do this, then the time delta would be equal to loading the whole application, which can take sometimes few seconds, that's too much for frame time delta)
- Dbl cur_time=curTime(), new_rd=cur_time-_rt;
- // detect slow downs
- if(!_skip && new_rd>_rd*3) // if new delta is 3x bigger than old one, then most probably there's some system slow down or app loaded something, so skip update, it's important to check this on RD and then set it either way, because if we would be checking D or AD then skipping could go on and on (for example if we've just entered more complex level, and rendering takes now longer in each frame, then all subsequent frames would have delta much bigger than originally, and it would never stop skipping, however with RD we're just checking first frame of sudden drop, which then all next frames will be processed normally without skipping)
- if(D.sync() ? new_rd>(Abs(_rd-_rd_1)+Abs(_rd_1-_rd_2)+Abs(_rd-_rd_2))*5 : true) // when sync is enabled check also the deviations between frame deltas, because sometimes rendering can be jerky (1st frame is 15ms, 2nd frame is 2ms and 3rd is 48ms and so on) so by checking the amount of deviations we're preventing slow downs because of jerky rendering
- _skip=true;
- _rt=cur_time; _rd_2=_rd_1; _rd_1=_rd; _rd=new_rd; // set new values
- if(_skip)_skip--;else _ad=_sv_ad.update(_rd);
- _d =_ad*_speed;
- _at+=_ad;
- _st+=_ad;
- _t+= _d;
- _frame++;
- _frames_drawn++; if((_fps_time+=_rd)>=1)
- {
- _fps =_frames_drawn/_fps_time;
- _fps_time =0;
- _frames_drawn=0;
- }
- }
- /******************************************************************************/
- // MAIN
- /******************************************************************************/
- Bool EventOccurred(Flt event_time, Flt start_time, Flt dt)
- {
- return start_time<=event_time && start_time+dt>event_time;
- }
- Bool EventBetween(Flt event_time_from, Flt event_time_to, Flt start_time, Flt dt)
- {
- return start_time<=event_time_to && start_time+dt>=event_time_from;
- }
- /******************************************************************************/
- }
- /******************************************************************************/
|