mirror of https://github.com/MLXXXp/Arduboy2.git
Refactor nextFrame() and add setFrameDuration()
nextFrame() changes were in colaboration with @MrBlinky setFrameDuration() can be used as an alternative to setFrameRate()
This commit is contained in:
parent
4788b1ab01
commit
460e768ea9
|
@ -83,6 +83,7 @@ readUnitName KEYWORD2
|
|||
safeMode KEYWORD2
|
||||
saveOnOff KEYWORD2
|
||||
setCursor KEYWORD2
|
||||
setFrameDuration KEYWORD2
|
||||
setFrameRate KEYWORD2
|
||||
setRGBled KEYWORD2
|
||||
setTextBackground KEYWORD2
|
||||
|
|
|
@ -19,13 +19,9 @@ Arduboy2Base::Arduboy2Base()
|
|||
currentButtonState = 0;
|
||||
previousButtonState = 0;
|
||||
// frame management
|
||||
setFrameRate(60);
|
||||
frameCount = -1;
|
||||
nextFrameStart = 0;
|
||||
setFrameDuration(16);
|
||||
frameCount = 0;
|
||||
justRendered = false;
|
||||
// init not necessary, will be reset after first use
|
||||
// lastFrameStart
|
||||
// lastFrameDurationMs
|
||||
}
|
||||
|
||||
// functions called here should be public so users can create their
|
||||
|
@ -185,6 +181,11 @@ void Arduboy2Base::setFrameRate(uint8_t rate)
|
|||
eachFrameMillis = 1000 / rate;
|
||||
}
|
||||
|
||||
void Arduboy2Base::setFrameDuration(uint8_t duration)
|
||||
{
|
||||
eachFrameMillis = duration;
|
||||
}
|
||||
|
||||
bool Arduboy2Base::everyXFrames(uint8_t frames)
|
||||
{
|
||||
return frameCount % frames == 0;
|
||||
|
@ -192,38 +193,27 @@ bool Arduboy2Base::everyXFrames(uint8_t frames)
|
|||
|
||||
bool Arduboy2Base::nextFrame()
|
||||
{
|
||||
unsigned long now = millis();
|
||||
bool tooSoonForNextFrame = now < nextFrameStart;
|
||||
uint8_t now = (uint8_t) millis();
|
||||
uint8_t frameDurationMs = now - thisFrameStart;
|
||||
|
||||
if (justRendered) {
|
||||
lastFrameDurationMs = now - lastFrameStart;
|
||||
lastFrameDurationMs = frameDurationMs;
|
||||
justRendered = false;
|
||||
return false;
|
||||
}
|
||||
else if (tooSoonForNextFrame) {
|
||||
// if we have MORE than 1ms to spare (hence our comparison with 2),
|
||||
// lets sleep for power savings. We don't compare against 1 to avoid
|
||||
// potential rounding errors - say we're actually 0.5 ms away, but a 1
|
||||
// is returned if we go to sleep we might sleep a full 1ms and then
|
||||
// we'd be running the frame slighly late. So the last 1ms we stay
|
||||
// awake for perfect timing.
|
||||
|
||||
// This is likely trading power savings for absolute timing precision
|
||||
// and the power savings might be the better goal. At 60 FPS trusting
|
||||
// chance here might actually achieve a "truer" 60 FPS than the 16ms
|
||||
// frame duration we get due to integer math.
|
||||
|
||||
// We should be woken up by timer0 every 1ms, so it's ok to sleep.
|
||||
if ((uint8_t)(nextFrameStart - now) >= 2)
|
||||
else if (frameDurationMs < eachFrameMillis) {
|
||||
// Only idle if at least a full millisecond remains, since idle() may
|
||||
// sleep the processor until the next millisecond timer interrupt.
|
||||
if (++frameDurationMs < eachFrameMillis) {
|
||||
idle();
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
// pre-render
|
||||
justRendered = true;
|
||||
lastFrameStart = now;
|
||||
nextFrameStart = now + eachFrameMillis;
|
||||
thisFrameStart = now;
|
||||
frameCount++;
|
||||
|
||||
return true;
|
||||
|
|
|
@ -660,17 +660,47 @@ class Arduboy2Base : public Arduboy2Core
|
|||
*
|
||||
* \details
|
||||
* Set the frame rate, in frames per second, used by `nextFrame()` to update
|
||||
* frames at a given rate. If this function isn't used, the default rate will
|
||||
* be 60.
|
||||
* frames at a given rate. If this function or `setFrameDuration()`
|
||||
* isn't used, the default rate will be 60 (actually 62.5, see note below).
|
||||
*
|
||||
* Normally, the frame rate would be set to the desired value once, at the
|
||||
* start of the game, but it can be changed at any time to alter the frame
|
||||
* update rate.
|
||||
*
|
||||
* \see nextFrame()
|
||||
* \note
|
||||
* \parblock
|
||||
* The given rate is internally converted to a frame duration in milliseconds,
|
||||
* rounded down to the nearest integer. Therefore, the actual rate will be
|
||||
* equal to or higher than the rate given.
|
||||
|
||||
* For example, 60 FPS would be 16.67ms per frame. This will be rounded down
|
||||
* to 16ms, giving an actual frame rate of 62.5 FPS.
|
||||
* \endparblock
|
||||
*
|
||||
* \see nextFrame() setFrameDuration()
|
||||
*/
|
||||
void setFrameRate(uint8_t rate);
|
||||
|
||||
/** \brief
|
||||
* Set the frame rate, used by the frame control functions, by giving
|
||||
* the duration of each frame.
|
||||
*
|
||||
* \param duration The desired duration of each frame in milliseconds.
|
||||
*
|
||||
* \details
|
||||
* Set the frame rate by specifying the duration of each frame in
|
||||
* milliseconds. This is used by `nextFrame()` to update frames at a
|
||||
* given rate. If this function or `setFrameRate()` isn't used,
|
||||
* the default will be 16ms per frame.
|
||||
*
|
||||
* Normally, the frame rate would be set to the desired value once, at the
|
||||
* start of the game, but it can be changed at any time to alter the frame
|
||||
* update rate.
|
||||
*
|
||||
* \see nextFrame() setFrameRate()
|
||||
*/
|
||||
void setFrameDuration(uint8_t duration);
|
||||
|
||||
/** \brief
|
||||
* Indicate that it's time to render the next frame.
|
||||
*
|
||||
|
@ -694,7 +724,7 @@ class Arduboy2Base : public Arduboy2Core
|
|||
* }
|
||||
* \endcode
|
||||
*
|
||||
* \see setFrameRate() nextFrameDEV()
|
||||
* \see setFrameRate() setFrameDuration() nextFrameDEV()
|
||||
*/
|
||||
bool nextFrame();
|
||||
|
||||
|
@ -1120,8 +1150,7 @@ class Arduboy2Base : public Arduboy2Core
|
|||
|
||||
// For frame funcions
|
||||
uint8_t eachFrameMillis;
|
||||
unsigned long lastFrameStart;
|
||||
unsigned long nextFrameStart;
|
||||
uint8_t thisFrameStart;
|
||||
bool justRendered;
|
||||
uint8_t lastFrameDurationMs;
|
||||
};
|
||||
|
|
Loading…
Reference in New Issue