diff --git a/cocos2dx/CCDirector.cpp b/cocos2dx/CCDirector.cpp index 203e7e3cc5..366e415391 100644 --- a/cocos2dx/CCDirector.cpp +++ b/cocos2dx/CCDirector.cpp @@ -125,6 +125,10 @@ bool CCDirector::init(void) // FPS m_bDisplayFPS = false; m_nFrames = 0; + m_pszFPS = new char[10]; + m_fExpectedFrameRate = 1 / m_dAnimationInterval; + + // paused ? m_bPaused = false; @@ -136,6 +140,7 @@ bool CCDirector::init(void) m_bIsContentScaleSupported =false; m_pLastUpdate = new struct cc_timeval(); + m_pLastComputeTime = new struct cc_timeval(); // create autorelease pool NSPoolManager::getInstance()->push(); @@ -162,8 +167,13 @@ CCDirector::~CCDirector(void) NSPoolManager::getInstance()->pop(); // delete m_pLastUpdate - delete m_pLastUpdate; - m_pLastUpdate = NULL; + CCX_SAFE_DELETE(m_pLastUpdate); + + // delete last compute time + CCX_SAFE_DELETE(m_pLastComputeTime); + + // delete fps string + delete []m_pszFPS; } void CCDirector::setGLDefaultValues(void) @@ -181,11 +191,8 @@ void CCDirector::setGLDefaultValues(void) #if CC_DIRECTOR_FAST_FPS if (! m_pFPSLabel) { -// CCTexture2DPixelFormat currentFormat = CCTexture2D::defaultAlphaPixelFormat(); -// CCTexture2D::setDefaultAlphaPixelFormat(kCCTexture2DPixelFormat_RGBA4444); m_pFPSLabel = CCLabel::labelWithString("00.0", "XXX", 24); m_pFPSLabel->retain(); - /*CCTexture2D::setDefaultAlphaPixelFormat(currentFormat);*/ } #endif } @@ -261,7 +268,7 @@ void CCDirector::calculateDeltaTime(void) m_fDeltaTime = 0; m_bNextDeltaTimeZero = false; } - else + else { m_fDeltaTime = (now.tv_sec - m_pLastUpdate->tv_sec) + (now.tv_usec - m_pLastUpdate->tv_usec) / 1000000.0f; m_fDeltaTime = MAX(0, m_fDeltaTime); @@ -656,8 +663,6 @@ void CCDirector::end(void) void CCDirector::setNextScene(void) { -// bool runningIsTransition = dynamic_cast(m_pRunningScene) != NULL; -// bool newIsTransition = dynamic_cast(m_pNextScene) != NULL; ccSceneFlag runningSceneType = ccNormalScene; ccSceneFlag newSceneType = m_pNextScene->getSceneType(); @@ -691,7 +696,6 @@ void CCDirector::setNextScene(void) m_pNextScene->retain(); m_pNextScene = NULL; - /*if (! runningIsTransition && m_pRunningScene)*/ if (! (runningSceneType & ccTransitionScene) && m_pRunningScene) { m_pRunningScene->onEnter(); @@ -754,25 +758,29 @@ void CCDirector::preMainLoop(void) // updates the FPS every frame void CCDirector::showFPS(void) { - ++m_nFrames; - m_fAccumDt += m_fDeltaTime; - - if (m_fAccumDt > CC_DIRECTOR_FPS_INTERVAL) - { - m_fFrameRate = m_nFrames / m_fAccumDt; - m_nFrames = 0; - m_fAccumDt = 0; - - char *str = new char[10]; - sprintf(str, "%.1f", m_fFrameRate); - m_pFPSLabel->setString(str); - delete [] str; - } + sprintf(m_pszFPS, "%.1f", m_fFrameRate); + m_pFPSLabel->setString(m_pszFPS); m_pFPSLabel->draw(); } #endif // CC_DIRECTOR_FAST_FPS +void CCDirector::computeFrameRate() +{ + static bool bFirstTime = true; + struct cc_timeval now; + + CCTime::gettimeofdayCocos2d(&now, NULL); + if (! bFirstTime) + { + m_fAccumDt += ((now.tv_sec - m_pLastComputeTime->tv_sec) + (now.tv_usec - m_pLastComputeTime->tv_usec) / 1000000.0f); + m_fFrameRate = m_nFrames / m_fAccumDt; + } + + bFirstTime = false; + *m_pLastComputeTime = now; +} + #if CC_ENABLE_PROFILERS void CCDirector::showProfilers() { @@ -798,26 +806,23 @@ void CCDisplayLinkDirector::startAnimation(void) } m_bInvalid = false; - - // approximate frame rate - // assumes device refreshes at 60 fps - //int frameInterval = (int) floor(animationInterval * 60.0f); - - //CCLOG(@"cocos2d: Frame interval: %d", frameInterval); - - //displayLink = [NSClassFromString(@"CADisplayLink") displayLinkWithTarget:self selector:@selector(preMainLoop:)]; - //[displayLink setFrameInterval:frameInterval]; - //[displayLink addToRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode]; } void CCDisplayLinkDirector::preMainLoop(void) { if (! m_bInvalid) { - drawScene(); - - // release the objects - NSPoolManager::getInstance()->pop(); + // compute frame rate + computeFrameRate(); + + if (m_fFrameRate < m_fExpectedFrameRate) + { + drawScene(); + ++m_nFrames; + + // release the objects + NSPoolManager::getInstance()->pop(); + } } } @@ -829,6 +834,7 @@ void CCDisplayLinkDirector::stopAnimation(void) void CCDisplayLinkDirector::setAnimationInterval(double dValue) { m_dAnimationInterval = dValue; + m_fExpectedFrameRate = 1 / m_dAnimationInterval; if (! m_bInvalid) { stopAnimation(); diff --git a/cocos2dx/include/CCDirector.h b/cocos2dx/include/CCDirector.h index 11b018d453..7ddc6c1e05 100644 --- a/cocos2dx/include/CCDirector.h +++ b/cocos2dx/include/CCDirector.h @@ -207,7 +207,7 @@ public: /** Get the FPS value */ inline double getAnimationInterval(void) { return m_dAnimationInterval; } - /** Set the FPS value. Now it has not effect. */ + /** Set the FPS value. */ virtual void setAnimationInterval(double dValue); /** Whether or not to display the FPS on the bottom-left corner */ @@ -343,7 +343,7 @@ public: /** Pauses the running scene. The running scene will be _drawed_ but all scheduled timers will be paused - While paused, the draw rate will be 4 FPS to reduce CPU consuption + While paused, the draw rate will be 4 FPS to reduce CPU consumption */ void pause(void); @@ -354,13 +354,13 @@ public: void resume(void); /** Stops the animation. Nothing will be drawn. The main loop won't be triggered anymore. - If you wan't to pause your animation call [pause] instead. + If you don't want to pause your animation call [pause] instead. */ virtual void stopAnimation(void); /** The main loop is triggered again. Call this function only if [stopAnimation] was called earlier - @warning Dont' call this function to start the main loop. To run the main loop call runWithScene + @warning Don't call this function to start the main loop. To run the main loop call runWithScene */ virtual void startAnimation(void); @@ -401,7 +401,7 @@ public: - kCCDirectorTypeDisplayLink Each Director has it's own benefits, limitations. - Now we only support DisplayLink director, so it has not effect + Now we only support DisplayLink director, so it has not effect. This method should be called before any other call to the director. @@ -434,6 +434,9 @@ protected: */ void recalculateProjectionAndEAGLViewSize(); +protected: + void computeFrameRate(void); + protected: /* The CCXEGLView, where everything is rendered */ cocos2d::CCXEGLView *m_pobOpenGLView; @@ -454,6 +457,7 @@ protected: int m_nFrames; ccTime m_fAccumDt; ccTime m_fFrameRate; + ccTime m_fExpectedFrameRate; #if CC_DIRECTOR_FAST_FPS CCLabel *m_pFPSLabel; #endif @@ -477,6 +481,9 @@ protected: /* last time the main loop was updated */ struct cc_timeval *m_pLastUpdate; + /* last time the frame fate is computed */ + struct cc_timeval *m_pLastComputeTime; + /* delta time since last tick to main loop */ ccTime m_fDeltaTime; @@ -497,6 +504,9 @@ protected: /* contentScaleFactor could be simulated */ bool m_bIsContentScaleSupported; + + /* store the fps string */ + char *m_pszFPS; #if CC_ENABLE_PROFILERS ccTime m_fAccumDtForProfiler; @@ -507,12 +517,9 @@ protected: @brief DisplayLinkDirector is a Director that synchronizes timers with the refresh rate of the display. Features and Limitations: - - Only available on 3.1+ - Scheduled timers & drawing are synchronizes with the refresh rate of the display - Only supports animation intervals of 1/60 1/30 & 1/15 - It is the recommended Director if the SDK is 3.1 or newer - @since v0.8.2 */ class CCDisplayLinkDirector : public CCDirector @@ -520,7 +527,6 @@ class CCDisplayLinkDirector : public CCDirector public: CCDisplayLinkDirector(void) {} - //static CCDisplayLinkDirector* getSharedDirector(void); virtual void preMainLoop(void); virtual void setAnimationInterval(double dValue); virtual void startAnimation(void);