//--------------------------------------------------------------------------------
void CPUTGuiController::Update()
{
    if (mActiveControlPanelSlotID == CPUT_CONTROL_ID_INVALID)
        return;
    if(mRecalculate)
    {
        RecalculateLayout();
        mRecalculate = false;
    }
    if(!mUpdateBuffers)
        return;
    mUpdateBuffers = false;

    HEAPCHECK;
    static double timeSinceLastFPSUpdate = 0;
    static int    framesSinceLastFPSUpdate = 0;
    static double avgFPS = 0;
    static CPUT_RECT windowRect = {0, 0, 0, 0};
	static int lastControlsInPanel = 0;

	int controlsInPanel = GetNumberOfControlsInPanel();
    if( 0 == controlsInPanel && lastControlsInPanel == controlsInPanel)
    {
		lastControlsInPanel = controlsInPanel;
        return;
    }
	lastControlsInPanel = controlsInPanel;


    // check and see if any of the controls resized themselves
    int ControlCount=GetNumberOfControlsInPanel();

    // 'clear' the buffer by resetting the pointer to the head
    mUberBufferIndex = 0;

    int ii=0;
    while(ii<ControlCount)
    {
        CPUTControl *pControl = mControlPanelIDList[mActiveControlPanelSlotID]->mControlList[ii];

        // don't draw the focus control - draw it last so it stays on 'top'
        if(mpFocusControl != pControl)
        {
            pControl->Draw(mpMirrorBuffer, &mUberBufferIndex, mBufferSize);                    
        }
        ii++;
        HEAPCHECK
    }

    // do the 'focused' control last so it stays on top (i.e. dropdowns)
    if(mpFocusControl)
    {
        mpFocusControl->Draw(mpMirrorBuffer, &mUberBufferIndex, mBufferSize);
    }
        
    //API Specific
    UpdateUberBuffers();
    HEAPCHECK
    return;
}
// Draw - must be positioned after all the controls are defined
//--------------------------------------------------------------------------------
void CPUTGuiControllerDX11::Draw(ID3D11DeviceContext *pImmediateContext)
{
    HEAPCHECK;

    if( 0 != GetNumberOfControlsInPanel())
    {
        SetGUIDrawingState(pImmediateContext);
    }
    else
    {
        return;
    }

    ID3D11VertexShader *pVertexShader = mpGUIVertexShader->GetNativeVertexShader();
    ID3D11PixelShader  *pPixelShader  = mpGUIPixelShader->GetNativePixelShader();

    // if any of the controls have announced they are dirty, then rebuild the mirror buffer and rebind
    if(mUberBufferDirty)
    {
        
        // if a resize was flagged, do it now.  
        if(mRecalculateLayout)
        {
            RecalculateLayout();
        }


        // 'clear' the buffer by resetting the pointer to the head
        mUberBufferIndex = 0;
        mTextUberBufferIndex = 0;
        mFocusedControlBufferIndex = 0;
        mFocusedControlTextBufferIndex = 0;

        int ii=0;
        while(ii<GetNumberOfControlsInPanel())
        {
            CPUTControl *pControl = mControlPanelIDList[mActiveControlPanelSlotID]->mControlList[ii];

            // don't draw the focus control - draw it last so it stays on 'top'
            if(mpFocusControl != pControl)
            {
                switch(pControl->GetType())
                {
                case CPUT_BUTTON:
                    ((CPUTButton*)pControl)->DrawIntoBuffer(mpMirrorBuffer, &mUberBufferIndex, mUberBufferMax, mpTextMirrorBuffer, &mTextUberBufferIndex, CPUT_GUI_BUFFER_STRING_SIZE);                    
                    break;
                case CPUT_CHECKBOX:
                    ((CPUTCheckbox*)pControl)->DrawIntoBuffer(mpMirrorBuffer, &mUberBufferIndex, mUberBufferMax, mpTextMirrorBuffer, &mTextUberBufferIndex, CPUT_GUI_BUFFER_STRING_SIZE);
                    break;
                case CPUT_SLIDER:
                    ((CPUTSlider*)pControl)->DrawIntoBuffer(mpMirrorBuffer, &mUberBufferIndex, mUberBufferMax, mpTextMirrorBuffer, &mTextUberBufferIndex, CPUT_GUI_BUFFER_STRING_SIZE);
                    break;
                case CPUT_DROPDOWN:
                    ((CPUTDropdown*)pControl)->DrawIntoBuffer(mpMirrorBuffer, &mUberBufferIndex, mUberBufferMax, mpTextMirrorBuffer, &mTextUberBufferIndex, CPUT_GUI_BUFFER_STRING_SIZE);
                    break;

                case CPUT_STATIC:
                    ((CPUTText*)pControl)->DrawIntoBuffer(mpTextMirrorBuffer, &mTextUberBufferIndex, CPUT_GUI_BUFFER_STRING_SIZE);
                    break;
                }
            }
            ii++;
            HEAPCHECK
        }

        // do the 'focused' control last so it stays on top (i.e. dropdowns)
        if(mpFocusControl)
        {
            switch(mpFocusControl->GetType())
            {
            case CPUT_BUTTON:
                ((CPUTButton*)mpFocusControl)->DrawIntoBuffer(mpFocusedControlMirrorBuffer, &mFocusedControlBufferIndex, mUberBufferMax, mpFocusedControlTextMirrorBuffer, &mFocusedControlTextBufferIndex, CPUT_GUI_BUFFER_STRING_SIZE);                    
                break;
            case CPUT_CHECKBOX:
                ((CPUTCheckbox*)mpFocusControl)->DrawIntoBuffer(mpFocusedControlMirrorBuffer, &mFocusedControlBufferIndex, mUberBufferMax, mpFocusedControlTextMirrorBuffer, &mFocusedControlTextBufferIndex, CPUT_GUI_BUFFER_STRING_SIZE);
                break;
            case CPUT_SLIDER:
                ((CPUTSlider*)mpFocusControl)->DrawIntoBuffer(mpFocusedControlMirrorBuffer, &mFocusedControlBufferIndex, mUberBufferMax, mpFocusedControlTextMirrorBuffer, &mFocusedControlTextBufferIndex, CPUT_GUI_BUFFER_STRING_SIZE);
                break;
            case CPUT_DROPDOWN:
                ((CPUTDropdown*)mpFocusControl)->DrawIntoBuffer(mpFocusedControlMirrorBuffer, &mFocusedControlBufferIndex, mUberBufferMax, mpFocusedControlTextMirrorBuffer, &mFocusedControlTextBufferIndex, CPUT_GUI_BUFFER_STRING_SIZE);
                break;
            case CPUT_STATIC:
                ((CPUTText*)mpFocusControl)->DrawIntoBuffer(mpFocusedControlMirrorBuffer, &mFocusedControlTextBufferIndex, CPUT_GUI_BUFFER_STRING_SIZE);
                break;
            }
        }
        
                
        // update the uber-buffers with the control graphics
        UpdateUberBuffers(pImmediateContext);

        // Clear dirty flag on uberbuffer
        mUberBufferDirty = false;

    }
    HEAPCHECK



    // calculate the fps
    double elapsed = mpFPSTimer->GetElapsedTime();
    double fps = 1.0 / elapsed;
    mLastFPS = (float) fps;

	mFPSAvg[mFPSInst] = (float) fps;
	mFPSInst++;
	if(mFPSInst == AVG_FRAMES)
		mFPSInst = 0;

	float total = 0.0f;
	for(int i = 0; i < AVG_FRAMES; i++)
	{
		total += mFPSAvg[i];
	}

    int windowWidth, windowHeight;
    CPUTOSServices *pServices = CPUTOSServices::GetOSServices( );
    pServices->GetClientDimensions( &windowWidth, &windowHeight );

    // if we're drawing the FPS counter - update that
    // We do this independently of uber-buffer updates since we'll have FPS updates every frame,
    // but likely not have control updates every frame
    if(mbDrawFPS)
    {
        // calculate the time elapsed since last frame
        bool UberBufferWasDirty = mUberBufferDirty;

        cString Data;
        {
            wchar_t wcstring[CPUT_MAX_STRING_LENGTH];
            float avgFps = total/(float)AVG_FRAMES;
            swprintf_s(&wcstring[0], CPUT_MAX_STRING_LENGTH, _L("Window res: %d x %d, AVG FPS:%.2f \t(FPS:%.2f)  "), windowWidth, windowHeight, avgFps, fps);
            Data=wcstring;
        }
		// build the FPS string
        cString FPS = Data;
        mpFPSCounter->SetText(FPS); 

        // 'draw' the string into the buffer
        mFPSBufferIndex = 0;
        mpFPSCounter->DrawIntoBuffer(mpFPSMirrorBuffer, &mFPSBufferIndex, CPUT_GUI_BUFFER_STRING_SIZE);

        // update the DirectX vertex buffer
        ASSERT(CPUT_GUI_BUFFER_STRING_SIZE > mFocusedControlTextBufferIndex, _L("CPUT GUI: Too many strings for default-sized uber-buffer.  Increase CPUT_GUI_BUFFER_STRING_SIZE"));
        pImmediateContext->UpdateSubresource(mpFPSDirectXBuffer, 0, NULL, mpFPSMirrorBuffer, mFPSBufferIndex*sizeof(CPUTGUIVertex), 0);
        
        // start next frame timer
        mpFPSTimer->StartTimer();
        if(false == UberBufferWasDirty)
        {
            mUberBufferDirty = false;
        }
    }


    // set up orthographic display
    GUIConstantBufferVS ConstantBufferMatrices;
    float znear = 0.1f;
    float zfar = 100.0f;
	DirectX::XMMATRIX m;

    m = DirectX::XMMatrixOrthographicOffCenterLH(0, (float)windowWidth, (float)windowHeight, 0, znear, zfar);
    ConstantBufferMatrices.Projection = XMMatrixTranspose( m );

    // set the vertex shader
    pImmediateContext->VSSetShader( pVertexShader, NULL, 0 );
    UINT VertexStride = sizeof(CPUTGUIVertex);
    UINT VertexOffset = 0;
    pImmediateContext->IASetVertexBuffers( 0, 1, &mpUberBuffer, &VertexStride, &VertexOffset );

    m = DirectX::XMMatrixIdentity();
    ConstantBufferMatrices.Model = XMMatrixTranspose( m );
    pImmediateContext->UpdateSubresource( mpConstantBufferVS, 0, NULL, &ConstantBufferMatrices, 0, 0 );
    pImmediateContext->VSSetConstantBuffers( 0, 1, &mpConstantBufferVS );

    // -- draw the normal controls --    
    // draw the control graphics
    pImmediateContext->PSSetShader( pPixelShader, NULL, 0 );
    pImmediateContext->PSSetShaderResources( 0, 1, &mpControlTextureAtlasView );    
    pImmediateContext->Draw(mUberBufferIndex,0);

    // draw the control's text
    pImmediateContext->PSSetShaderResources( 0, 1, &mpTextTextureAtlasView );
    pImmediateContext->IASetVertexBuffers( 0, 1, &mpTextUberBuffer, &VertexStride, &VertexOffset );
    // draw the text uber-buffer
    pImmediateContext->Draw(mTextUberBufferIndex,0);

    // draw the FPS counter
    if(mbDrawFPS)
    {
        pImmediateContext->IASetVertexBuffers( 0, 1, &mpFPSDirectXBuffer, &VertexStride, &VertexOffset );
        pImmediateContext->Draw(mFPSBufferIndex, 0);
    }
    
    // -- draw the focused control --
    // Draw the focused control's graphics
    pImmediateContext->PSSetShader( pPixelShader, NULL, 0 );
    pImmediateContext->PSSetShaderResources( 0, 1, &mpControlTextureAtlasView );
    pImmediateContext->IASetVertexBuffers( 0, 1, &mpFocusedControlBuffer, &VertexStride, &VertexOffset );
    // draw the uber-buffer
    pImmediateContext->Draw(mFocusedControlBufferIndex,0);


    // Draw the focused control's text
    pImmediateContext->PSSetShaderResources( 0, 1, &mpTextTextureAtlasView );
    pImmediateContext->IASetVertexBuffers( 0, 1, &mpFocusedControlTextBuffer, &VertexStride, &VertexOffset );
    // draw the text uber-buffer
    pImmediateContext->Draw(mFocusedControlTextBufferIndex,0);


    // restore the drawing state
    ClearGUIDrawingState(pImmediateContext);
    HEAPCHECK;
}
// Draw - must be positioned after all the controls are defined
//--------------------------------------------------------------------------------
void CPUTGuiControllerOGL::Draw()
{
    HEAPCHECK;

    static double timeSinceLastFPSUpdate = 0;
    static int    framesSinceLastFPSUpdate = 0;
    static double avgFPS = 0;
    static double minFrameTime = 999;
    static double maxFrameTime = 0;
    static CPUT_RECT windowRect = {0, 0, 0, 0};

    if( 0 == GetNumberOfControlsInPanel())
    {
        return;
    }


    // check and see if any of the controls resized themselves
    int ControlCount=GetNumberOfControlsInPanel();
    bool ResizingNeeded = false;
    for(int ii=0; ii<ControlCount; ii++)
    {
        CPUTControl *pControl = mControlPanelIDList[mActiveControlPanelSlotID]->mControlList[ii];
        if(true == pControl->ControlResizedItself())
        {
            ResizingNeeded = true;
            pControl->ControlResizingHandled();
        }
    }

    // if any of the controls resized, then re-do the autoarrangment
    if(true == ResizingNeeded)
    {
        this->Resize();
    }

    // Now check to see if any controls' graphics are dirty
    for(int ii=0; ii<ControlCount; ii++)
    {
        CPUTControl *pControl = mControlPanelIDList[mActiveControlPanelSlotID]->mControlList[ii];
        if(true == pControl->ControlGraphicsDirty())
        {
            mUberBufferDirty = true;
            break;
        }        
    }

    // if any of the controls have announced they are dirty, then rebuild the mirror buffer and update the GFX buffer
    if(mUberBufferDirty)
    {
        
        // if a resize was flagged, do it now.  
        if(mRecalculateLayout)
        {
            RecalculateLayout();
            mRecalculateLayout = false;
        }


        // 'clear' the buffer by resetting the pointer to the head
        mUberBufferIndex = 0;
        mTextUberBufferIndex = 0;
        mFocusedControlBufferIndex = 0;
        mFocusedControlTextBufferIndex = 0;

        int ii=0;
        while(ii<GetNumberOfControlsInPanel())
        {
            CPUTControl *pControl = mControlPanelIDList[mActiveControlPanelSlotID]->mControlList[ii];

            // don't draw the focus control - draw it last so it stays on 'top'
            if(mpFocusControl != pControl)
            {
                switch(pControl->GetType())
                {
                case CPUT_BUTTON:
                    ((CPUTButton*)pControl)->DrawIntoBuffer(mpMirrorBuffer, &mUberBufferIndex, mUberBufferMax, mpTextMirrorBuffer, &mTextUberBufferIndex, CPUT_GUI_BUFFER_STRING_SIZE);                    
                    break;
                case CPUT_CHECKBOX:
                    ((CPUTCheckbox*)pControl)->DrawIntoBuffer(mpMirrorBuffer, &mUberBufferIndex, mUberBufferMax, mpTextMirrorBuffer, &mTextUberBufferIndex, CPUT_GUI_BUFFER_STRING_SIZE);
                    break;
                case CPUT_SLIDER:
                    ((CPUTSlider*)pControl)->DrawIntoBuffer(mpMirrorBuffer, &mUberBufferIndex, mUberBufferMax, mpTextMirrorBuffer, &mTextUberBufferIndex, CPUT_GUI_BUFFER_STRING_SIZE);
                    break;
                case CPUT_DROPDOWN:
                    ((CPUTDropdown*)pControl)->DrawIntoBuffer(mpMirrorBuffer, &mUberBufferIndex, mUberBufferMax, mpTextMirrorBuffer, &mTextUberBufferIndex, CPUT_GUI_BUFFER_STRING_SIZE);
                    break;

                case CPUT_STATIC:
                    ((CPUTText*)pControl)->DrawIntoBuffer(mpTextMirrorBuffer, &mTextUberBufferIndex, CPUT_GUI_BUFFER_STRING_SIZE);
                    break;
                }
            }
            ii++;
            HEAPCHECK
        }

        // do the 'focused' control last so it stays on top (i.e. dropdowns)
        if(mpFocusControl)
        {
            switch(mpFocusControl->GetType())
            {
            case CPUT_BUTTON:
                ((CPUTButton*)mpFocusControl)->DrawIntoBuffer(mpFocusedControlMirrorBuffer, &mFocusedControlBufferIndex, mUberBufferMax, mpFocusedControlTextMirrorBuffer, &mFocusedControlTextBufferIndex, CPUT_GUI_BUFFER_STRING_SIZE);                    
                break;
            case CPUT_CHECKBOX:
                ((CPUTCheckbox*)mpFocusControl)->DrawIntoBuffer(mpFocusedControlMirrorBuffer, &mFocusedControlBufferIndex, mUberBufferMax, mpFocusedControlTextMirrorBuffer, &mFocusedControlTextBufferIndex, CPUT_GUI_BUFFER_STRING_SIZE);
                break;
            case CPUT_SLIDER:
                ((CPUTSlider*)mpFocusControl)->DrawIntoBuffer(mpFocusedControlMirrorBuffer, &mFocusedControlBufferIndex, mUberBufferMax, mpFocusedControlTextMirrorBuffer, &mFocusedControlTextBufferIndex, CPUT_GUI_BUFFER_STRING_SIZE);
                break;
            case CPUT_DROPDOWN:
                ((CPUTDropdown*)mpFocusControl)->DrawIntoBuffer(mpFocusedControlMirrorBuffer, &mFocusedControlBufferIndex, mUberBufferMax, mpFocusedControlTextMirrorBuffer, &mFocusedControlTextBufferIndex, CPUT_GUI_BUFFER_STRING_SIZE);
                break;
            case CPUT_STATIC:
                ((CPUTText*)mpFocusControl)->DrawIntoBuffer(mpFocusedControlMirrorBuffer, &mFocusedControlTextBufferIndex, CPUT_GUI_BUFFER_STRING_SIZE);
                break;
            }
        }
        
                
        // update the uber-buffers with the control graphics
        UpdateUberBuffers();

        // Clear dirty flag on uberbuffer
        mUberBufferDirty = false;

    }
    HEAPCHECK

    if( mpConstantBufferVS )
    {
		// set up orthographic display
		int windowWidth, windowHeight;
		float znear = 0.1f;
		float zfar = 100.0f;
		float4x4 m;

		pWindow->GetClientDimensions( &windowWidth, &windowHeight );
		m = float4x4OrthographicOffCenterLH(0, (float)windowWidth, (float)windowHeight, 0, znear, zfar);
    
	    GUIConstantBufferVS ConstantBufferMatrices;
	    ConstantBufferMatrices.Projection = m;
        m = float4x4Identity();
	    ConstantBufferMatrices.Model = m; 
        GL_CHECK(glBindBuffer(GL_UNIFORM_BUFFER, mpConstantBufferVS->GetBufferID()));
        GL_CHECK(glBufferSubData(GL_UNIFORM_BUFFER, 0, sizeof(GUIConstantBufferVS), &ConstantBufferMatrices));
        GL_CHECK(glBindBuffer(GL_UNIFORM_BUFFER, 0));
	}

    CPUTRenderParameters params;
    mpControlMaterial->GetMaterialEffects()[0]->SetRenderStates(params);

    glDisable(GL_CULL_FACE);
    glDisable(GL_DEPTH_TEST);

	// draw the control graphics
	CPUTRenderParameters p;
	mpUberBuffer->Draw(p, NULL);
    
    mpTextMaterial->GetMaterialEffects()[0]->SetRenderStates(params);
    // draw text things here
    // draw the FPS counter
	mpTextUberBuffer->Draw(p, NULL);

    mpControlMaterial->GetMaterialEffects()[0]->SetRenderStates(params);
    mpFocusedControlBuffer->Draw(p, NULL);
    
	// draw focused control
	mpTextMaterial->GetMaterialEffects()[0]->SetRenderStates(params);
    mpFocusedControlTextBuffer->Draw(p, NULL);
    
	glEnable(GL_CULL_FACE);
    glDisable(GL_DEPTH_TEST);
	GL_CHECK(glBindBuffer(GL_UNIFORM_BUFFER, 0));

    HEAPCHECK;
}