├── .travis.yml ├── LICENSE ├── README.md ├── hertz.cc ├── hertz.cpp └── hertz.hpp /.travis.yml: -------------------------------------------------------------------------------- 1 | language: cpp 2 | sudo: required 3 | 4 | compiler: 5 | - clang 6 | - gcc 7 | 8 | install: 9 | - wget --quiet -O - https://raw.githubusercontent.com/r-lyeh/depot/master/travis.pre.sh | bash -x 10 | 11 | script: 12 | - wget --quiet -O - https://raw.githubusercontent.com/r-lyeh/depot/master/travis.build.sh | bash -x 13 | # - wget --quiet -O - https://raw.githubusercontent.com/r-lyeh/depot/master/travis.run.sh | bash -x 14 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2015 r-lyeh (https://github.com/r-lyeh) 2 | 3 | This software is provided 'as-is', without any express or implied 4 | warranty. In no event will the authors be held liable for any damages 5 | arising from the use of this software. 6 | 7 | Permission is granted to anyone to use this software for any purpose, 8 | including commercial applications, and to alter it and redistribute it 9 | freely, subject to the following restrictions: 10 | 11 | 1. The origin of this software must not be misrepresented; you must not 12 | claim that you wrote the original software. If you use this software 13 | in a product, an acknowledgment in the product documentation would be 14 | appreciated but is not required. 15 | 2. Altered source versions must be plainly marked as such, and must not be 16 | misrepresented as being the original software. 17 | 3. This notice may not be removed or altered from any source distribution. 18 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | Hertz :watch: 2 | ==== 3 | 4 | - Hertz is a simple framerate locker (C++11) 5 | - Hertz features auto-frameskip. 6 | - Hertz features dynamic/variable framerate locking. 7 | - Hertz is tiny (~75 LOC), cross-platform, self-contained and header-only. 8 | - Hertz is zlib/libpng licensed. 9 | 10 | ### API 11 | ```c++ 12 | double /*fps*/ hertz::lock( 60 /*Hz*/, []{/*logic*/}, []{/*render*/} ); 13 | void hertz::unlock(); // quit 14 | ``` 15 | 16 | ### Changelog 17 | - v1.0.0 (2015/12/05): Add unlock function 18 | - v1.0.0 (2015/09/19): Initial commit 19 | -------------------------------------------------------------------------------- /hertz.cc: -------------------------------------------------------------------------------- 1 | #define HERTZ_BUILD_SAMPLE 2 | #include "hertz.hpp" 3 | -------------------------------------------------------------------------------- /hertz.cpp: -------------------------------------------------------------------------------- 1 | #include "hertz.hpp" 2 | -------------------------------------------------------------------------------- /hertz.hpp: -------------------------------------------------------------------------------- 1 | // Hertz, simple framerate locker. based on code by /u/concavator (ref: http://goo.gl/Ry50A4) 2 | // - rlyeh. zlib/libpng licensed 3 | // 4 | // features: 5 | // [x] auto-frameskip 6 | // [x] dynamic/variable framerate locking 7 | 8 | #pragma once 9 | #include 10 | #include 11 | #include 12 | 13 | #define HERTZ_VERSION "1.0.1" /* (2015/12/05) Add unlock function 14 | #define HERTZ_VERSION "1.0.0" // (2015/09/19) Initial commit */ 15 | 16 | namespace hertz { 17 | // function that locks your logic and render to desired framerate (in HZ). 18 | // returns number of current fps 19 | template 20 | static inline 21 | double lock( signed HZ, FNU &update, FNR &render ) { 22 | // rw vars 23 | static volatile unsigned hz = 60, isGameRunning = 1, maxframeskip = 10; 24 | // ro vars 25 | static volatile unsigned fps = 0; 26 | // private vars 27 | static volatile unsigned timer_counter = 0, loop_counter = 0; 28 | // private threaded timer 29 | static struct install { 30 | install() { 31 | std::thread([&]{ 32 | std::chrono::microseconds acc( 0 ), third( 300000 ); 33 | while( isGameRunning ) { 34 | // update timer 35 | timer_counter++; 36 | std::chrono::microseconds duration( int(1000000/hz) ); 37 | std::this_thread::sleep_for( duration ); 38 | // update fps 3 times per second 39 | acc += duration; 40 | if( acc >= third ) { 41 | acc -= acc; 42 | static int before = loop_counter; 43 | fps = int( std::round( (loop_counter - before) * 3.3333333 ) ); 44 | before = loop_counter; 45 | } 46 | } 47 | isGameRunning = 1; 48 | }).detach(); 49 | } 50 | } timer; 51 | 52 | if( HZ < 0 ) { 53 | isGameRunning = 0; 54 | return 1; 55 | } 56 | 57 | hz = HZ > 0 ? HZ : hz; 58 | 59 | // we got too far ahead, cpu idle wait 60 | while( loop_counter > timer_counter && isGameRunning ) { 61 | std::this_thread::yield(); 62 | } 63 | 64 | // max auto frameskip is 10, ie, even if speed is low paint at least one frame every 10 65 | if( timer_counter > loop_counter + 10 ) { 66 | timer_counter = loop_counter; 67 | } 68 | 69 | loop_counter++; 70 | 71 | // only draw if we are fast enough, otherwise skip the frame 72 | update(); 73 | if( loop_counter >= timer_counter ) { 74 | render(); 75 | } 76 | return fps; 77 | } 78 | 79 | static inline void unlock() { 80 | auto nil = []{}; 81 | hertz::lock( -1, nil, nil ); 82 | } 83 | } 84 | 85 | 86 | #ifdef HERTZ_BUILD_SAMPLE 87 | 88 | #ifdef _WIN32 89 | #include 90 | #pragma comment(lib, "user32.lib") 91 | #endif 92 | 93 | #include 94 | #include 95 | #include 96 | #include 97 | 98 | int main() { 99 | unsigned HZ = 60, updates = 0, frames = 0, fps = 0; 100 | 101 | auto update = [&]{ 102 | updates++; 103 | #ifdef _WIN32 104 | static auto &once = std::cout << "Keys: up, down, escape, space" << std::endl; 105 | if( GetAsyncKeyState(VK_UP) & 0x8000 ) HZ+=(std::min)((std::max)(int(HZ*0.01), 1), 5); 106 | if( GetAsyncKeyState(VK_DOWN) & 0x8000 ) if(HZ > (std::max)(int(HZ*0.01), 1)) HZ-=(std::max)(int(HZ*0.01), 1); 107 | if( GetAsyncKeyState(VK_ESCAPE) & 0x8000 ) exit(0); 108 | if( GetAsyncKeyState(VK_SPACE) & 0x8000 ) Sleep( rand() % 80 ); 109 | #endif 110 | }; 111 | 112 | auto render = [&]{ 113 | frames++; 114 | char bar[] = "\\|/-"; 115 | auto current_time = time(NULL); 116 | auto sec = localtime(¤t_time)->tm_sec; 117 | 118 | printf( "(%d/%d) [%c] updates %02ds [%c] frames \r", 119 | fps, HZ, bar[updates%4], sec, bar[frames%4] ); 120 | }; 121 | 122 | for(;;) { 123 | fps = hertz::lock( HZ, update, render ); 124 | } 125 | 126 | hertz::unlock(); 127 | } 128 | 129 | #endif --------------------------------------------------------------------------------