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
|
safeMode KEYWORD2
|
||||||
saveOnOff KEYWORD2
|
saveOnOff KEYWORD2
|
||||||
setCursor KEYWORD2
|
setCursor KEYWORD2
|
||||||
|
setFrameDuration KEYWORD2
|
||||||
setFrameRate KEYWORD2
|
setFrameRate KEYWORD2
|
||||||
setRGBled KEYWORD2
|
setRGBled KEYWORD2
|
||||||
setTextBackground KEYWORD2
|
setTextBackground KEYWORD2
|
||||||
|
|
|
@ -19,13 +19,9 @@ Arduboy2Base::Arduboy2Base()
|
||||||
currentButtonState = 0;
|
currentButtonState = 0;
|
||||||
previousButtonState = 0;
|
previousButtonState = 0;
|
||||||
// frame management
|
// frame management
|
||||||
setFrameRate(60);
|
setFrameDuration(16);
|
||||||
frameCount = -1;
|
frameCount = 0;
|
||||||
nextFrameStart = 0;
|
|
||||||
justRendered = false;
|
justRendered = false;
|
||||||
// init not necessary, will be reset after first use
|
|
||||||
// lastFrameStart
|
|
||||||
// lastFrameDurationMs
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// functions called here should be public so users can create their
|
// functions called here should be public so users can create their
|
||||||
|
@ -185,6 +181,11 @@ void Arduboy2Base::setFrameRate(uint8_t rate)
|
||||||
eachFrameMillis = 1000 / rate;
|
eachFrameMillis = 1000 / rate;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Arduboy2Base::setFrameDuration(uint8_t duration)
|
||||||
|
{
|
||||||
|
eachFrameMillis = duration;
|
||||||
|
}
|
||||||
|
|
||||||
bool Arduboy2Base::everyXFrames(uint8_t frames)
|
bool Arduboy2Base::everyXFrames(uint8_t frames)
|
||||||
{
|
{
|
||||||
return frameCount % frames == 0;
|
return frameCount % frames == 0;
|
||||||
|
@ -192,38 +193,27 @@ bool Arduboy2Base::everyXFrames(uint8_t frames)
|
||||||
|
|
||||||
bool Arduboy2Base::nextFrame()
|
bool Arduboy2Base::nextFrame()
|
||||||
{
|
{
|
||||||
unsigned long now = millis();
|
uint8_t now = (uint8_t) millis();
|
||||||
bool tooSoonForNextFrame = now < nextFrameStart;
|
uint8_t frameDurationMs = now - thisFrameStart;
|
||||||
|
|
||||||
if (justRendered) {
|
if (justRendered) {
|
||||||
lastFrameDurationMs = now - lastFrameStart;
|
lastFrameDurationMs = frameDurationMs;
|
||||||
justRendered = false;
|
justRendered = false;
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
else if (tooSoonForNextFrame) {
|
else if (frameDurationMs < eachFrameMillis) {
|
||||||
// if we have MORE than 1ms to spare (hence our comparison with 2),
|
// Only idle if at least a full millisecond remains, since idle() may
|
||||||
// lets sleep for power savings. We don't compare against 1 to avoid
|
// sleep the processor until the next millisecond timer interrupt.
|
||||||
// potential rounding errors - say we're actually 0.5 ms away, but a 1
|
if (++frameDurationMs < eachFrameMillis) {
|
||||||
// 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)
|
|
||||||
idle();
|
idle();
|
||||||
|
}
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// pre-render
|
// pre-render
|
||||||
justRendered = true;
|
justRendered = true;
|
||||||
lastFrameStart = now;
|
thisFrameStart = now;
|
||||||
nextFrameStart = now + eachFrameMillis;
|
|
||||||
frameCount++;
|
frameCount++;
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
|
|
|
@ -660,17 +660,47 @@ class Arduboy2Base : public Arduboy2Core
|
||||||
*
|
*
|
||||||
* \details
|
* \details
|
||||||
* Set the frame rate, in frames per second, used by `nextFrame()` to update
|
* 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
|
* frames at a given rate. If this function or `setFrameDuration()`
|
||||||
* be 60.
|
* 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
|
* 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
|
* start of the game, but it can be changed at any time to alter the frame
|
||||||
* update rate.
|
* 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);
|
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
|
/** \brief
|
||||||
* Indicate that it's time to render the next frame.
|
* Indicate that it's time to render the next frame.
|
||||||
*
|
*
|
||||||
|
@ -694,7 +724,7 @@ class Arduboy2Base : public Arduboy2Core
|
||||||
* }
|
* }
|
||||||
* \endcode
|
* \endcode
|
||||||
*
|
*
|
||||||
* \see setFrameRate() nextFrameDEV()
|
* \see setFrameRate() setFrameDuration() nextFrameDEV()
|
||||||
*/
|
*/
|
||||||
bool nextFrame();
|
bool nextFrame();
|
||||||
|
|
||||||
|
@ -1120,8 +1150,7 @@ class Arduboy2Base : public Arduboy2Core
|
||||||
|
|
||||||
// For frame funcions
|
// For frame funcions
|
||||||
uint8_t eachFrameMillis;
|
uint8_t eachFrameMillis;
|
||||||
unsigned long lastFrameStart;
|
uint8_t thisFrameStart;
|
||||||
unsigned long nextFrameStart;
|
|
||||||
bool justRendered;
|
bool justRendered;
|
||||||
uint8_t lastFrameDurationMs;
|
uint8_t lastFrameDurationMs;
|
||||||
};
|
};
|
||||||
|
|
Loading…
Reference in New Issue