/*
 * This source file is part of KEOS (Free 3D Engine)
 * For the latest info, see http://www.keosengine.org/
 * E-mails : thierry.vouriot@keosengine.org, yeri@keosengine.org
 * 
 * This program is free software; you can redistribute it and/or modify it under
 * the terms of the GNU Lesser General Public License as published by the Free Software
 * Foundation; either version 2 of the License, or (at your option) any later
 * version.
 *
 * This program is distributed in the hope that it will be useful, but WITHOUT
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
 * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public License along with
 * this program; if not, write to the Free Software Foundation, Inc., 59 Temple
 * Place - Suite 330, Boston, MA 02111-1307, USA, or go to
 * http://www.gnu.org/copyleft/lesser.txt.
 *
 */
#include "KeosRenderTarget.h"
#include "KeosRoot.h"
#include "KeosTimer.h"
#include "KeosLogger.h"

namespace Keos 
{
    //=======================================================================
    // IRenderSystem implementation
    //=======================================================================
    
    //-----------------------------------------------------------------------
    IRenderTarget::IRenderTarget()
    {
        m_pRenderApp = NULL;

        // Default to no stats display
        m_bActive = true;
        m_bAutoUpdate = true;
        
        m_pTimer = CRoot::Instance().GetTimer();
        ResetStatistics();
    }

    //-----------------------------------------------------------------------
    IRenderTarget::~IRenderTarget()
    {
        if (m_pRenderApp && m_pRenderApp->IsInit()) {
            m_pRenderApp->Release();
        }
        ILogger::Log("<-- Destroy RenderTarget '%s'", m_strName.c_str());
    }

    //-----------------------------------------------------------------------
    void IRenderTarget::GetMetrics(uint& nWidth, uint& nHeight, uint& nColourDepth)
    {
        nWidth = m_nWidth;
        nHeight = m_nHeight;
        nColourDepth = m_nColourDepth;
    }

    //-----------------------------------------------------------------------
    void IRenderTarget::Init(void)
    {
        ILogger::Log("--> Init RenderTarget '%s'", m_strName.c_str());
        m_pRenderApp->Init();
        m_pRenderApp->SetInit(true);
    }

    //-----------------------------------------------------------------------
    void IRenderTarget::Update(void)
    {  
        m_Stats.triangleCount = 0;

        // Update statistics (always on top)
        UpdateStats();
 
        m_pRenderApp->Update();
        m_pRenderApp->Render();
    }

    //-----------------------------------------------------------------------
    void IRenderTarget::ResetStatistics(void)
    {
        m_Stats.avgFPS = 0.0;
        m_Stats.bestFPS = 0.0;
        m_Stats.lastFPS = 0.0;
        m_Stats.worstFPS = 999.0;
        m_Stats.triangleCount = 0;
        m_Stats.bestFrameTime = 999999;
        m_Stats.worstFrameTime = 0;

        m_nLastTime = m_pTimer->GetMilliseconds();
        m_nLastSecond = m_nLastTime;
        m_nFrameCount = 0;
    }

    //-----------------------------------------------------------------------
    void IRenderTarget::UpdateStats(void)
    {
        ++m_nFrameCount;
        unsigned long thisTime = m_pTimer->GetMilliseconds();

        // check frame time
        unsigned long frameTime = thisTime - m_nLastTime ;
        m_nLastTime = thisTime ;

        m_Stats.bestFrameTime = std::min(m_Stats.bestFrameTime, frameTime);
        m_Stats.worstFrameTime = std::max(m_Stats.worstFrameTime, frameTime);

        // check if new second (update only once per second)
        if (thisTime - m_nLastSecond > 1000) 
        { 
            // new second - not 100% precise
            m_Stats.lastFPS = (float)m_nFrameCount / (float)(thisTime - m_nLastSecond) * 1000.0;
            
            if (m_Stats.avgFPS == 0)
                m_Stats.avgFPS = m_Stats.lastFPS;
            else
                m_Stats.avgFPS = (m_Stats.avgFPS + m_Stats.lastFPS) / 2; // not strictly correct, but good enough

            m_Stats.bestFPS = std::max(m_Stats.bestFPS, m_Stats.lastFPS);
            m_Stats.worstFPS = std::min(m_Stats.worstFPS, m_Stats.lastFPS);

            m_nLastSecond = thisTime ;
            m_nFrameCount  = 0;

        }
    }

} // namespace Keos        
