<commit_before>#include <stdio.h>
#include <tchar.h>
#include <D3DX9.h>

#include "dx9font.h"

//-----------------------------------------------------------------------------
// Custom vertex types for rendering text
//-----------------------------------------------------------------------------
#define MAX_NUM_VERTICES 50*6

struct FONT2DVERTEX { D3DXVECTOR4 p;   DWORD color;     FLOAT tu, tv; };
struct FONT3DVERTEX { D3DXVECTOR3 p;   D3DXVECTOR3 n;   FLOAT tu, tv; };

#define D3DFVF_FONT2DVERTEX (D3DFVF_XYZRHW|D3DFVF_DIFFUSE|D3DFVF_TEX1)
#define D3DFVF_FONT3DVERTEX (D3DFVF_XYZ|D3DFVF_NORMAL|D3DFVF_TEX1)

inline FONT2DVERTEX InitFont2DVertex( const D3DXVECTOR4& p, D3DCOLOR color,
                                      FLOAT tu, FLOAT tv )
{
    FONT2DVERTEX v;   v.p = p;   v.color = color;   v.tu = tu;   v.tv = tv;
    return v;
}

inline FONT3DVERTEX InitFont3DVertex( const D3DXVECTOR3& p, const D3DXVECTOR3& n,
                                      FLOAT tu, FLOAT tv )
{
    FONT3DVERTEX v;   v.p = p;   v.n = n;   v.tu = tu;   v.tv = tv;
    return v;
}

//-----------------------------------------------------------------------------
// Name: CD3DFont()
// Desc: Font class constructor
//-----------------------------------------------------------------------------
Dx9Font::Dx9Font(
    LPDIRECT3DDEVICE9 pd3dDevice
    )
{
    m_pd3dDevice           = NULL;
    m_pTexture             = NULL;
    m_pVB                  = NULL;

    m_pStateBlockSaved     = NULL;
    m_pStateBlockDrawText  = NULL;

    // Keep a local copy of the device
    m_pd3dDevice = pd3dDevice;
}

//-----------------------------------------------------------------------------
// Name: ~CD3DFont()
// Desc: Font class destructor
//-----------------------------------------------------------------------------
Dx9Font::~Dx9Font()
{
    InvalidateDeviceObjects();
    DeleteDeviceObjects();
}

DWORD
Dx9Font::GetMaxTextureWidth()
{
    D3DCAPS9 d3dCaps;

    m_pd3dDevice->GetDeviceCaps( &d3dCaps );

    return d3dCaps.MaxTextureWidth;
}

HRESULT
Dx9Font::CreateTexture()
{
    HRESULT hr;
    D3DFORMAT format;

    if (PIXEL_DEPTH == 16)
        format = D3DFMT_A4R4G4B4;
    else if (PIXEL_DEPTH == 32)
        format = D3DFMT_A8R8G8B8;

    hr = m_pd3dDevice->CreateTexture(
                        m_dwTexWidth,
                        m_dwTexHeight,
                        1,
                        0,
                        format,
                        D3DPOOL_MANAGED,
                        &m_pTexture,
                        NULL
                        );

    return hr;
}

VOID
Dx9Font::LockTexture(
    D3DLOCKED_RECT* pLockedRect
    )
{
    m_pTexture->LockRect( 0, pLockedRect, 0, 0 );
}

VOID
Dx9Font::UnlockTexture()
{
    m_pTexture->UnlockRect(0);
}

//-----------------------------------------------------------------------------
// Name: RestoreDeviceObjects()
// Desc:
//-----------------------------------------------------------------------------
HRESULT Dx9Font::RestoreDeviceObjects()
{
    HRESULT hr;

    // Create vertex buffer for the letters
    int vertexSize = max( sizeof(FONT2DVERTEX), sizeof(FONT3DVERTEX ) );
    if( FAILED( hr = m_pd3dDevice->CreateVertexBuffer( MAX_NUM_VERTICES * vertexSize,
                                                       D3DUSAGE_WRITEONLY | D3DUSAGE_DYNAMIC, 0,
                                                       D3DPOOL_DEFAULT, &m_pVB, NULL ) ) )
    {
        return hr;
    }

    // Create the state blocks for rendering text
    for( UINT which=0; which<2; which++ )
    {
        m_pd3dDevice->BeginStateBlock();
        m_pd3dDevice->SetTexture( 0, m_pTexture );

        if ( D3DFONT_ZENABLE & m_dwFontFlags )
            m_pd3dDevice->SetRenderState( D3DRS_ZENABLE, TRUE );
        else
            m_pd3dDevice->SetRenderState( D3DRS_ZENABLE, FALSE );

        m_pd3dDevice->SetRenderState( D3DRS_ALPHABLENDENABLE, TRUE );
        m_pd3dDevice->SetRenderState( D3DRS_SRCBLEND,   D3DBLEND_SRCALPHA );
        m_pd3dDevice->SetRenderState( D3DRS_DESTBLEND,  D3DBLEND_INVSRCALPHA );
        m_pd3dDevice->SetRenderState( D3DRS_ALPHATESTENABLE,  TRUE );
        m_pd3dDevice->SetRenderState( D3DRS_ALPHAREF,         0x08 );
        m_pd3dDevice->SetRenderState( D3DRS_ALPHAFUNC,  D3DCMP_GREATEREQUAL );
        m_pd3dDevice->SetRenderState( D3DRS_FILLMODE,   D3DFILL_SOLID );
        m_pd3dDevice->SetRenderState( D3DRS_CULLMODE,   D3DCULL_CCW );
        m_pd3dDevice->SetRenderState( D3DRS_STENCILENABLE,    FALSE );
        m_pd3dDevice->SetRenderState( D3DRS_CLIPPING,         TRUE );
        m_pd3dDevice->SetRenderState( D3DRS_CLIPPLANEENABLE,  FALSE );
        m_pd3dDevice->SetRenderState( D3DRS_VERTEXBLEND,      D3DVBF_DISABLE );
        m_pd3dDevice->SetRenderState( D3DRS_INDEXEDVERTEXBLENDENABLE, FALSE );
        m_pd3dDevice->SetRenderState( D3DRS_FOGENABLE,        FALSE );
        m_pd3dDevice->SetRenderState( D3DRS_COLORWRITEENABLE,
            D3DCOLORWRITEENABLE_RED  | D3DCOLORWRITEENABLE_GREEN |
            D3DCOLORWRITEENABLE_BLUE | D3DCOLORWRITEENABLE_ALPHA );
        m_pd3dDevice->SetTextureStageState( 0, D3DTSS_COLOROP,   D3DTOP_MODULATE );
        m_pd3dDevice->SetTextureStageState( 0, D3DTSS_COLORARG1, D3DTA_TEXTURE );
        m_pd3dDevice->SetTextureStageState( 0, D3DTSS_COLORARG2, D3DTA_DIFFUSE );
        m_pd3dDevice->SetTextureStageState( 0, D3DTSS_ALPHAOP,   D3DTOP_MODULATE );
        m_pd3dDevice->SetTextureStageState( 0, D3DTSS_ALPHAARG1, D3DTA_TEXTURE );
        m_pd3dDevice->SetTextureStageState( 0, D3DTSS_ALPHAARG2, D3DTA_DIFFUSE );
        m_pd3dDevice->SetTextureStageState( 0, D3DTSS_TEXCOORDINDEX, 0 );
        m_pd3dDevice->SetTextureStageState( 0, D3DTSS_TEXTURETRANSFORMFLAGS, D3DTTFF_DISABLE );
        m_pd3dDevice->SetTextureStageState( 1, D3DTSS_COLOROP,   D3DTOP_DISABLE );
        m_pd3dDevice->SetTextureStageState( 1, D3DTSS_ALPHAOP,   D3DTOP_DISABLE );
        m_pd3dDevice->SetSamplerState( 0, D3DSAMP_MINFILTER, D3DTEXF_POINT );
        m_pd3dDevice->SetSamplerState( 0, D3DSAMP_MAGFILTER, D3DTEXF_POINT );
        m_pd3dDevice->SetSamplerState( 0, D3DSAMP_MIPFILTER, D3DTEXF_NONE );
        m_pd3dDevice->SetFVF( D3DFVF_FONT2DVERTEX );
        m_pd3dDevice->SetPixelShader( NULL );

        if( which==0 )
            m_pd3dDevice->EndStateBlock( &m_pStateBlockSaved );
        else
            m_pd3dDevice->EndStateBlock( &m_pStateBlockDrawText );
    }

    return S_OK;
}

//-----------------------------------------------------------------------------
// Name: InvalidateDeviceObjects()
// Desc: Destroys all device-dependent objects
//-----------------------------------------------------------------------------
HRESULT Dx9Font::InvalidateDeviceObjects()
{
    if (m_pVB)
        m_pVB->Release();

    if (m_pStateBlockSaved)
        m_pStateBlockSaved->Release();

    if (m_pStateBlockDrawText)
        m_pStateBlockDrawText->Release();

    m_pVB = NULL;
    m_pStateBlockSaved = NULL;
    m_pStateBlockDrawText = NULL;

    return S_OK;
}

//-----------------------------------------------------------------------------
// Name: DeleteDeviceObjects()
// Desc: Destroys all device-dependent objects
//-----------------------------------------------------------------------------
HRESULT Dx9Font::DeleteDeviceObjects()
{
    if (m_pTexture)
        m_pTexture->Release();

    m_pTexture = NULL;
    m_pd3dDevice = NULL;

    return S_OK;
}

//-----------------------------------------------------------------------------
// Name: DrawText()
// Desc: Draws 2D text. Note that sx and sy are in pixels
//-----------------------------------------------------------------------------
HRESULT Dx9Font::DrawText( FLOAT sx, FLOAT sy, DWORD dwColor, TCHAR* strText, DWORD dwFlags )
{
    if( m_pd3dDevice == NULL )
        return E_FAIL;

    // Setup renderstate
    m_pStateBlockSaved->Capture();
    m_pStateBlockDrawText->Apply();
    //m_pd3dDevice->SetFVF( D3DFVF_FONT2DVERTEX );
    //m_pd3dDevice->SetPixelShader( NULL );
    m_pd3dDevice->SetStreamSource( 0, m_pVB, 0, sizeof(FONT2DVERTEX) );

    // Set filter states
    if( dwFlags & D3DFONT_FILTERED )
    {
        m_pd3dDevice->SetSamplerState( 0, D3DSAMP_MINFILTER, D3DTEXF_LINEAR );
        m_pd3dDevice->SetSamplerState( 0, D3DSAMP_MAGFILTER, D3DTEXF_LINEAR );
    }

    if( dwFlags & D3DFONT_RIGHT ) {
        SIZE sz;
        GetTextExtent( strText, &sz );
        sx -= (FLOAT)sz.cx;
    } else if( dwFlags & D3DFONT_CENTERED ) {
        SIZE sz;
        GetTextExtent( strText, &sz );
        sx -= (FLOAT)sz.cx/2.0f;
    }

    // Adjust for character spacing
    sx -= m_dwSpacing;
    FLOAT fStartX = sx;

    // Fill vertex buffer
    FONT2DVERTEX* pVertices = NULL;
    DWORD         dwNumTriangles = 0;
    m_pVB->Lock( 0, 0, (void**)&pVertices, D3DLOCK_DISCARD );

    while( *strText )
    {
        TCHAR c = *strText++;

        if( c == _T('\n') )
        {
            sx = fStartX;
            sy += (m_fTexCoords[0][3]-m_fTexCoords[0][1])*m_dwTexHeight;
        }

        if( (c-32) < 0 || (c-32) >= (NUMBER_OF_CHARACTERS+1)-32 )
            continue;

        FLOAT tx1 = m_fTexCoords[c-32][0];
        FLOAT ty1 = m_fTexCoords[c-32][1];
        FLOAT tx2 = m_fTexCoords[c-32][2];
        FLOAT ty2 = m_fTexCoords[c-32][3];

        FLOAT w = (tx2-tx1) *  m_dwTexWidth / m_fTextScale;
        FLOAT h = (ty2-ty1) * m_dwTexHeight / m_fTextScale;

        if( c != _T(' ') )
        {
            *pVertices++ = InitFont2DVertex( D3DXVECTOR4(sx+0-0.5f,sy+h-0.5f,0.9f,1.0f), dwColor, tx1, ty2 );
            *pVertices++ = InitFont2DVertex( D3DXVECTOR4(sx+0-0.5f,sy+0-0.5f,0.9f,1.0f), dwColor, tx1, ty1 );
            *pVertices++ = InitFont2DVertex( D3DXVECTOR4(sx+w-0.5f,sy+h-0.5f,0.9f,1.0f), dwColor, tx2, ty2 );
            *pVertices++ = InitFont2DVertex( D3DXVECTOR4(sx+w-0.5f,sy+0-0.5f,0.9f,1.0f), dwColor, tx2, ty1 );
            *pVertices++ = InitFont2DVertex( D3DXVECTOR4(sx+w-0.5f,sy+h-0.5f,0.9f,1.0f), dwColor, tx2, ty2 );
            *pVertices++ = InitFont2DVertex( D3DXVECTOR4(sx+0-0.5f,sy+0-0.5f,0.9f,1.0f), dwColor, tx1, ty1 );
            dwNumTriangles += 2;

            if( dwNumTriangles*3 > (MAX_NUM_VERTICES-6) )
            {
                // Unlock, render, and relock the vertex buffer
                m_pVB->Unlock();
                m_pd3dDevice->DrawPrimitive( D3DPT_TRIANGLELIST, 0, dwNumTriangles );
                pVertices = NULL;
                m_pVB->Lock( 0, 0, (void**)&pVertices, D3DLOCK_DISCARD );
                dwNumTriangles = 0L;
            }
        }

        sx += w - (2 * m_dwSpacing);
    }

    // Unlock and render the vertex buffer
    m_pVB->Unlock();
    if( dwNumTriangles > 0 )
        m_pd3dDevice->DrawPrimitive( D3DPT_TRIANGLELIST, 0, dwNumTriangles );

    // Restore the modified renderstates
    m_pStateBlockSaved->Apply();

    return S_OK;
}
<commit_msg>fixed overlay not working on IDirect3DDevice9Ex based games; more specifically HL2 engine based games<commit_after>#include <stdio.h>
#include <tchar.h>
#include <D3DX9.h>

#include "dx9font.h"

//-----------------------------------------------------------------------------
// Custom vertex types for rendering text
//-----------------------------------------------------------------------------
#define MAX_NUM_VERTICES 50*6

struct FONT2DVERTEX { D3DXVECTOR4 p;   DWORD color;     FLOAT tu, tv; };
struct FONT3DVERTEX { D3DXVECTOR3 p;   D3DXVECTOR3 n;   FLOAT tu, tv; };

#define D3DFVF_FONT2DVERTEX (D3DFVF_XYZRHW|D3DFVF_DIFFUSE|D3DFVF_TEX1)
#define D3DFVF_FONT3DVERTEX (D3DFVF_XYZ|D3DFVF_NORMAL|D3DFVF_TEX1)

inline FONT2DVERTEX InitFont2DVertex( const D3DXVECTOR4& p, D3DCOLOR color,
                                      FLOAT tu, FLOAT tv )
{
    FONT2DVERTEX v;   v.p = p;   v.color = color;   v.tu = tu;   v.tv = tv;
    return v;
}

inline FONT3DVERTEX InitFont3DVertex( const D3DXVECTOR3& p, const D3DXVECTOR3& n,
                                      FLOAT tu, FLOAT tv )
{
    FONT3DVERTEX v;   v.p = p;   v.n = n;   v.tu = tu;   v.tv = tv;
    return v;
}

//-----------------------------------------------------------------------------
// Name: CD3DFont()
// Desc: Font class constructor
//-----------------------------------------------------------------------------
Dx9Font::Dx9Font(
    LPDIRECT3DDEVICE9 pd3dDevice
    )
{
    m_pd3dDevice           = NULL;
    m_pTexture             = NULL;
    m_pVB                  = NULL;

    m_pStateBlockSaved     = NULL;
    m_pStateBlockDrawText  = NULL;

    // Keep a local copy of the device
    m_pd3dDevice = pd3dDevice;
}

//-----------------------------------------------------------------------------
// Name: ~CD3DFont()
// Desc: Font class destructor
//-----------------------------------------------------------------------------
Dx9Font::~Dx9Font()
{
    InvalidateDeviceObjects();
    DeleteDeviceObjects();
}

DWORD
Dx9Font::GetMaxTextureWidth()
{
    D3DCAPS9 d3dCaps;

    m_pd3dDevice->GetDeviceCaps( &d3dCaps );

    return d3dCaps.MaxTextureWidth;
}

HRESULT
Dx9Font::CreateTexture()
{
    HRESULT hr;
    D3DFORMAT format;

    if (PIXEL_DEPTH == 16)
        format = D3DFMT_A4R4G4B4;
    else if (PIXEL_DEPTH == 32)
        format = D3DFMT_A8R8G8B8;

    hr = m_pd3dDevice->CreateTexture(
        m_dwTexWidth,
        m_dwTexHeight,
        1,
        D3DUSAGE_DYNAMIC,
        format,
        D3DPOOL_DEFAULT,
        &m_pTexture,
        NULL
        );

    return hr;
}

VOID
Dx9Font::LockTexture(
    D3DLOCKED_RECT* pLockedRect
    )
{
    m_pTexture->LockRect( 0, pLockedRect, 0, 0 );
}

VOID
Dx9Font::UnlockTexture()
{
    m_pTexture->UnlockRect(0);
}

//-----------------------------------------------------------------------------
// Name: RestoreDeviceObjects()
// Desc:
//-----------------------------------------------------------------------------
HRESULT Dx9Font::RestoreDeviceObjects()
{
    HRESULT hr;

    // Create vertex buffer for the letters
    int vertexSize = max( sizeof(FONT2DVERTEX), sizeof(FONT3DVERTEX ) );
    if( FAILED( hr = m_pd3dDevice->CreateVertexBuffer( MAX_NUM_VERTICES * vertexSize,
                                                       D3DUSAGE_WRITEONLY | D3DUSAGE_DYNAMIC, 0,
                                                       D3DPOOL_DEFAULT, &m_pVB, NULL ) ) )
    {
        return hr;
    }

    // Create the state blocks for rendering text
    for( UINT which=0; which<2; which++ )
    {
        m_pd3dDevice->BeginStateBlock();
        m_pd3dDevice->SetTexture( 0, m_pTexture );

        if ( D3DFONT_ZENABLE & m_dwFontFlags )
            m_pd3dDevice->SetRenderState( D3DRS_ZENABLE, TRUE );
        else
            m_pd3dDevice->SetRenderState( D3DRS_ZENABLE, FALSE );

        m_pd3dDevice->SetRenderState( D3DRS_ALPHABLENDENABLE, TRUE );
        m_pd3dDevice->SetRenderState( D3DRS_SRCBLEND,   D3DBLEND_SRCALPHA );
        m_pd3dDevice->SetRenderState( D3DRS_DESTBLEND,  D3DBLEND_INVSRCALPHA );
        m_pd3dDevice->SetRenderState( D3DRS_ALPHATESTENABLE,  TRUE );
        m_pd3dDevice->SetRenderState( D3DRS_ALPHAREF,         0x08 );
        m_pd3dDevice->SetRenderState( D3DRS_ALPHAFUNC,  D3DCMP_GREATEREQUAL );
        m_pd3dDevice->SetRenderState( D3DRS_FILLMODE,   D3DFILL_SOLID );
        m_pd3dDevice->SetRenderState( D3DRS_CULLMODE,   D3DCULL_CCW );
        m_pd3dDevice->SetRenderState( D3DRS_STENCILENABLE,    FALSE );
        m_pd3dDevice->SetRenderState( D3DRS_CLIPPING,         TRUE );
        m_pd3dDevice->SetRenderState( D3DRS_CLIPPLANEENABLE,  FALSE );
        m_pd3dDevice->SetRenderState( D3DRS_VERTEXBLEND,      D3DVBF_DISABLE );
        m_pd3dDevice->SetRenderState( D3DRS_INDEXEDVERTEXBLENDENABLE, FALSE );
        m_pd3dDevice->SetRenderState( D3DRS_FOGENABLE,        FALSE );
        m_pd3dDevice->SetRenderState( D3DRS_COLORWRITEENABLE,
            D3DCOLORWRITEENABLE_RED  | D3DCOLORWRITEENABLE_GREEN |
            D3DCOLORWRITEENABLE_BLUE | D3DCOLORWRITEENABLE_ALPHA );
        m_pd3dDevice->SetTextureStageState( 0, D3DTSS_COLOROP,   D3DTOP_MODULATE );
        m_pd3dDevice->SetTextureStageState( 0, D3DTSS_COLORARG1, D3DTA_TEXTURE );
        m_pd3dDevice->SetTextureStageState( 0, D3DTSS_COLORARG2, D3DTA_DIFFUSE );
        m_pd3dDevice->SetTextureStageState( 0, D3DTSS_ALPHAOP,   D3DTOP_MODULATE );
        m_pd3dDevice->SetTextureStageState( 0, D3DTSS_ALPHAARG1, D3DTA_TEXTURE );
        m_pd3dDevice->SetTextureStageState( 0, D3DTSS_ALPHAARG2, D3DTA_DIFFUSE );
        m_pd3dDevice->SetTextureStageState( 0, D3DTSS_TEXCOORDINDEX, 0 );
        m_pd3dDevice->SetTextureStageState( 0, D3DTSS_TEXTURETRANSFORMFLAGS, D3DTTFF_DISABLE );
        m_pd3dDevice->SetTextureStageState( 1, D3DTSS_COLOROP,   D3DTOP_DISABLE );
        m_pd3dDevice->SetTextureStageState( 1, D3DTSS_ALPHAOP,   D3DTOP_DISABLE );
        m_pd3dDevice->SetSamplerState( 0, D3DSAMP_MINFILTER, D3DTEXF_POINT );
        m_pd3dDevice->SetSamplerState( 0, D3DSAMP_MAGFILTER, D3DTEXF_POINT );
        m_pd3dDevice->SetSamplerState( 0, D3DSAMP_MIPFILTER, D3DTEXF_NONE );
        m_pd3dDevice->SetFVF( D3DFVF_FONT2DVERTEX );
        m_pd3dDevice->SetPixelShader( NULL );

        if( which==0 )
            m_pd3dDevice->EndStateBlock( &m_pStateBlockSaved );
        else
            m_pd3dDevice->EndStateBlock( &m_pStateBlockDrawText );
    }

    return S_OK;
}

//-----------------------------------------------------------------------------
// Name: InvalidateDeviceObjects()
// Desc: Destroys all device-dependent objects
//-----------------------------------------------------------------------------
HRESULT Dx9Font::InvalidateDeviceObjects()
{
    if (m_pVB)
        m_pVB->Release();

    if (m_pStateBlockSaved)
        m_pStateBlockSaved->Release();

    if (m_pStateBlockDrawText)
        m_pStateBlockDrawText->Release();

    m_pVB = NULL;
    m_pStateBlockSaved = NULL;
    m_pStateBlockDrawText = NULL;

    return S_OK;
}

//-----------------------------------------------------------------------------
// Name: DeleteDeviceObjects()
// Desc: Destroys all device-dependent objects
//-----------------------------------------------------------------------------
HRESULT Dx9Font::DeleteDeviceObjects()
{
    if (m_pTexture)
        m_pTexture->Release();

    m_pTexture = NULL;
    m_pd3dDevice = NULL;

    return S_OK;
}

//-----------------------------------------------------------------------------
// Name: DrawText()
// Desc: Draws 2D text. Note that sx and sy are in pixels
//-----------------------------------------------------------------------------
HRESULT Dx9Font::DrawText( FLOAT sx, FLOAT sy, DWORD dwColor, TCHAR* strText, DWORD dwFlags )
{
    if( m_pd3dDevice == NULL )
        return E_FAIL;

    // Setup renderstate
    m_pStateBlockSaved->Capture();
    m_pStateBlockDrawText->Apply();
    //m_pd3dDevice->SetFVF( D3DFVF_FONT2DVERTEX );
    //m_pd3dDevice->SetPixelShader( NULL );
    m_pd3dDevice->SetStreamSource( 0, m_pVB, 0, sizeof(FONT2DVERTEX) );

    // Set filter states
    if( dwFlags & D3DFONT_FILTERED )
    {
        m_pd3dDevice->SetSamplerState( 0, D3DSAMP_MINFILTER, D3DTEXF_LINEAR );
        m_pd3dDevice->SetSamplerState( 0, D3DSAMP_MAGFILTER, D3DTEXF_LINEAR );
    }

    if( dwFlags & D3DFONT_RIGHT ) {
        SIZE sz;
        GetTextExtent( strText, &sz );
        sx -= (FLOAT)sz.cx;
    } else if( dwFlags & D3DFONT_CENTERED ) {
        SIZE sz;
        GetTextExtent( strText, &sz );
        sx -= (FLOAT)sz.cx/2.0f;
    }

    // Adjust for character spacing
    sx -= m_dwSpacing;
    FLOAT fStartX = sx;

    // Fill vertex buffer
    FONT2DVERTEX* pVertices = NULL;
    DWORD         dwNumTriangles = 0;
    m_pVB->Lock( 0, 0, (void**)&pVertices, D3DLOCK_DISCARD );

    while( *strText )
    {
        TCHAR c = *strText++;

        if( c == _T('\n') )
        {
            sx = fStartX;
            sy += (m_fTexCoords[0][3]-m_fTexCoords[0][1])*m_dwTexHeight;
        }

        if( (c-32) < 0 || (c-32) >= (NUMBER_OF_CHARACTERS+1)-32 )
            continue;

        FLOAT tx1 = m_fTexCoords[c-32][0];
        FLOAT ty1 = m_fTexCoords[c-32][1];
        FLOAT tx2 = m_fTexCoords[c-32][2];
        FLOAT ty2 = m_fTexCoords[c-32][3];

        FLOAT w = (tx2-tx1) *  m_dwTexWidth / m_fTextScale;
        FLOAT h = (ty2-ty1) * m_dwTexHeight / m_fTextScale;

        if( c != _T(' ') )
        {
            *pVertices++ = InitFont2DVertex( D3DXVECTOR4(sx+0-0.5f,sy+h-0.5f,0.9f,1.0f), dwColor, tx1, ty2 );
            *pVertices++ = InitFont2DVertex( D3DXVECTOR4(sx+0-0.5f,sy+0-0.5f,0.9f,1.0f), dwColor, tx1, ty1 );
            *pVertices++ = InitFont2DVertex( D3DXVECTOR4(sx+w-0.5f,sy+h-0.5f,0.9f,1.0f), dwColor, tx2, ty2 );
            *pVertices++ = InitFont2DVertex( D3DXVECTOR4(sx+w-0.5f,sy+0-0.5f,0.9f,1.0f), dwColor, tx2, ty1 );
            *pVertices++ = InitFont2DVertex( D3DXVECTOR4(sx+w-0.5f,sy+h-0.5f,0.9f,1.0f), dwColor, tx2, ty2 );
            *pVertices++ = InitFont2DVertex( D3DXVECTOR4(sx+0-0.5f,sy+0-0.5f,0.9f,1.0f), dwColor, tx1, ty1 );
            dwNumTriangles += 2;

            if( dwNumTriangles*3 > (MAX_NUM_VERTICES-6) )
            {
                // Unlock, render, and relock the vertex buffer
                m_pVB->Unlock();
                m_pd3dDevice->DrawPrimitive( D3DPT_TRIANGLELIST, 0, dwNumTriangles );
                pVertices = NULL;
                m_pVB->Lock( 0, 0, (void**)&pVertices, D3DLOCK_DISCARD );
                dwNumTriangles = 0L;
            }
        }

        sx += w - (2 * m_dwSpacing);
    }

    // Unlock and render the vertex buffer
    m_pVB->Unlock();
    if( dwNumTriangles > 0 )
        m_pd3dDevice->DrawPrimitive( D3DPT_TRIANGLELIST, 0, dwNumTriangles );

    // Restore the modified renderstates
    m_pStateBlockSaved->Apply();

    return S_OK;
}
<|endoftext|>


<commit_before>//
//  cgp-projects
//
//  Created by HUJI Computer Graphics course staff, 2013.
//  Tweaked by HUJI Computer Games Programming staff 2014
//  Expanded by Amir Blum 2015

// OpenGL Headers
#include <GL/glew.h>
#ifdef __APPLE__
#include <GLUT/glut.h>
#else
#include <GL/freeglut.h>
#endif

// OpenAL Headers
#ifdef __APPLE__
#include <OpenAL/al.h>
#include <OpenAL/alc.h>
#else
#include <AL/al.h>
#include <AL/alc.h>
#endif
#include <AL/alut.h>

// GLM headers
#define GLM_FORCE_RADIANS
#include <glm/glm.hpp>
#include <glm/gtc/matrix_transform.hpp>
#include <glm/gtc/type_ptr.hpp> // for glm::value_ptr

using namespace glm;

#include "World.h"

#include "ShaderIO.h"
#include "InputManager.h"
#include "Camera.h"

#include <iostream>

/** Internal Definitions */

#define	WINDOW_WIDTH         (1024) // initial width of the window               //
#define	WINDOW_HEIGHT         (768) // initial height of the window               //
#define	WINDOW_POS_X        (100) // initial X position of the window         //
#define	WINDOW_POS_Y        (100) // initial Y position of the window         //

#define RC_OK                 (0) // Everything went ok                       //
#define RC_INVALID_ARGUMENTS  (1) // Invalid arguments given to the program   //
#define RC_INPUT_ERROR        (2) // Invalid input to the program             //

#define	ARGUMENTS_PROGRAM     (0) // program name position on argv            //
#define	ARGUMENTS_INPUTFILE   (1) // given input file position on argv        //
#define	ARGUMENTS_REQUIRED    (2) // number of required arguments             //

/** Key definitions */

#define KEY_ESC            ('\e') // Key used to terminate the program - ESC  //
#define KEY_RESET          ('r')
#define KEY_FULLSCREEN     ('f')

/** display callback */
void display(void);

/** window reshape callback  */
void windowResize(int width, int height);

/** keyboardDown callback  */
void keyboardDown(unsigned char key, int x, int y);

/** keyboardUp callback  */
void keyboardUp(unsigned char key, int x, int y);

/** mouse click callback */
void mouse(int button, int state, int x, int y) ;

/** mouse dragging callback  */
void motion(int x, int y) ;

// Game-related objects
World *_world;

/** main function */
int main(int argc, char* argv[])
{
    std::cout << "Starting ex4..." << std::endl;

    // Initialize GLUT
    glutInit(&argc, argv) ;
#ifdef __APPLE__
    glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGBA | GLUT_DEPTH | GLUT_3_2_CORE_PROFILE) ;
#else
    glutInitContextVersion(3, 3);
    glutInitContextFlags(GLUT_FORWARD_COMPATIBLE | GLUT_DEBUG);
    glutInitContextProfile(GLUT_CORE_PROFILE);
    glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGBA | GLUT_DEPTH);
#endif
    glutInitWindowSize(WINDOW_WIDTH, WINDOW_HEIGHT);
    glutInitWindowPosition(WINDOW_POS_X, WINDOW_POS_Y);
    glutCreateWindow("CGP Ex 3");

    // Initialize GLEW
    glewExperimental = GL_TRUE;
    int glewStatus = glewInit();
    if (glewStatus != GLEW_OK) {
        std::cerr << "Unable to initialize GLEW ... exiting" << std::endl;
        exit(1);
    }

    // GLEW has a "bug" where it sets a glError. According to the wiki this
    // can be safely ignored, so we clear the error here:
    glGetError();

#ifdef __APPLE__
    GLint sync = 1;
    CGLSetParameter(CGLGetCurrentContext(), kCGLCPSwapInterval, &sync);
#endif

    // Enable opengl drawing features
    glEnable(GL_DEPTH_TEST);
    glDepthFunc(GL_LEQUAL);
    glEnable(GL_BLEND);
    glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);

    // Set callback functions:
    glutDisplayFunc(display) ;
    glutReshapeFunc(windowResize) ;
    glutKeyboardFunc(keyboardDown);
    glutKeyboardUpFunc(keyboardUp);
    glutMouseFunc(mouse);
    glutMotionFunc(motion);
    glutPassiveMotionFunc(motion);

    glutSetCursor(GLUT_CURSOR_NONE);

    // Initialize ALUT (& background music)
    alutInit(&argc, argv);

    // Initialize random seed
    srand(time(NULL));

    // Set up game
    _world = new World();

    // Set clear color to black:
    glClearColor(0.0f, 0.0f, 0.0f, 1.0f);

    // Start events/drawing loop
    glutMainLoop();

    return 0;
}

// Time
int oldTimeSinceStart = 0;
float physicsTimeStep = 1.0f / 50.0f;
float accumulator = 0.0f;

// FPS
int frames = 0;
int fpsCounter = 0;

void display(void)
{
    // Update the delta
    int timeSinceStart = glutGet(GLUT_ELAPSED_TIME);
    int deltaTime = timeSinceStart - oldTimeSinceStart;
    oldTimeSinceStart = timeSinceStart;

    float dt = (float)deltaTime / 1000.0f;
    if (dt > 0.25f) {
        dt = 0.25f;
    }

    // We fix the physics timestep based on the information in the following
    // article: http://gafferongames.com/game-physics/fix-your-timestep/
    accumulator += dt;
    while (accumulator >= physicsTimeStep) {
//        std::cout << "physics update" << std::endl;
        _world->recursiveFixedUpdate(physicsTimeStep);
        accumulator -= physicsTimeStep;
    }

    const double physicsInterpolation = accumulator / physicsTimeStep;

    // Update the game state
    _world->recursiveUpdate(dt);

    // Drawing time

    // Clear the screen buffer
    glClearColor(0.15f, 0.0f, 0.2f, 1.0f);
    glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT);

    // Tell the world to draw itself
    _world->recursiveRender();

    // Print fps
    frames++;
    fpsCounter += deltaTime;
    if (fpsCounter > 1000) {
        std::cout << (frames * 1000) / fpsCounter << " FPS" << std::endl;
        fpsCounter = fpsCounter - 1000;
        frames = 0;
    }

    // Swap those buffers so someone will actually see the results... //
    glutSwapBuffers();

    // Refresh the display
    glutPostRedisplay();
}

// This method is called when the window is resized
int _screenWidth, _screenHeight;
void windowResize(int w, int h)
{
    _screenWidth = w;
    _screenHeight = h;

    // set the new viewport //
    glViewport(0, 0, w, h);

    // set the perspective of the camera
    Camera::MainCamera()->resize(w, h);

    // Refresh the display //
    glutPostRedisplay();
}

void toggleFullscreen()
{
    static bool fullscreen = false;
    static int previousWidth, previousHeight;
    static int previousX, previousY;

    if (!fullscreen) {
        previousWidth = _screenWidth;
        previousHeight = _screenHeight;
        previousX = glutGet(GLUT_WINDOW_X);
        previousY = glutGet(GLUT_WINDOW_Y);

        glutFullScreen();

        fullscreen = true;
    } else {
        glutReshapeWindow(previousWidth, previousHeight);
        glutPositionWindow(previousX, previousY);

        fullscreen = false;
    }
}

/********************************************************************
 * Function  :	keyboard
 * Arguments :	key : the key that was pressed
 *              x   : x value of the current mouse location
 *              y   : y value of the current mouse location
 * Returns   : n/a
 * Throws    : n/a
 *
 * Purpose   : This function handles all the keyboard input from the user.
 *             It supports terminating the application when the KEY_QUIT is pressed.
 *
 \******************************************************************/
void keyboardDown(unsigned char key, int x, int y)
{
    unsigned int lower_key = tolower(key);

    if (lower_key == KEY_ESC)
    {
        exit(RC_OK);
    }
    else if (lower_key == KEY_RESET)
    {
        delete _world;
        _world = new World;
        Camera::MainCamera()->resize(_screenWidth, _screenHeight);
    }
    else if (lower_key == KEY_FULLSCREEN)
    {
        toggleFullscreen();
    }

    InputManager::Instance().handleKeyDown(lower_key, x, y);
}

/********************************************************************
 * Function  :	keyboardUp
 * Arguments :	key : the key that was relased
 *              x   : x value of the current mouse location
 *              y   : y value of the current mouse location
 * Returns   : n/a
 * Throws    : n/a
 *
 * Purpose   : This function handles all the keyboard input from the user.
 *             It supports terminating the application when the KEY_QUIT is pressed.
 *
 \******************************************************************/
void keyboardUp(unsigned char key, int x, int y)
{
    unsigned int lower_key = tolower(key);

    InputManager::Instance().handleKeyUp(lower_key, x, y);
}

/********************************************************************
 * Function  :   mouse
 * Arguments :   button  : the button that was engaged in some action
 *               state   : the new state of that button
 *               x       : x value of the current mouse location
 *               y       : y value of the current mouse location
 * Returns   :   n/a
 * Throws    :   n/a
 *
 * Purpose   :   This function handles mouse actions.
 *
 \******************************************************************/
void mouse(int button, int state, int x, int y)
{
    if(button == GLUT_LEFT_BUTTON)
    {

    }
    else if (button == GLUT_RIGHT_BUTTON)
    {

    }

    return;
}

/********************************************************************
 * Function  :   motion
 * Arguments :   x   : x value of the current mouse location
 *               y   : y value of the current mouse location
 * Returns   :   n/a
 * Throws    :   n/a
 *
 * Purpose   :   This function handles mouse dragging events.
 *
 \******************************************************************/
void motion(int x, int y)
{
    float oglX = x / _screenWidth;
    float oglY = y / _screenHeight;

    oglX = oglX * 2.0f - 1.0f;
    oglY = oglY * -2.0f + 1.0f;

    InputManager::Instance().handleMouseMove(oglX, oglY);
}
<commit_msg>Don't start physics until game has started<commit_after>//
//  cgp-projects
//
//  Created by HUJI Computer Graphics course staff, 2013.
//  Tweaked by HUJI Computer Games Programming staff 2014
//  Expanded by Amir Blum 2015

// OpenGL Headers
#include <GL/glew.h>
#ifdef __APPLE__
#include <GLUT/glut.h>
#else
#include <GL/freeglut.h>
#endif

// OpenAL Headers
#ifdef __APPLE__
#include <OpenAL/al.h>
#include <OpenAL/alc.h>
#else
#include <AL/al.h>
#include <AL/alc.h>
#endif
#include <AL/alut.h>

// GLM headers
#define GLM_FORCE_RADIANS
#include <glm/glm.hpp>
#include <glm/gtc/matrix_transform.hpp>
#include <glm/gtc/type_ptr.hpp> // for glm::value_ptr

using namespace glm;

#include "World.h"

#include "ShaderIO.h"
#include "InputManager.h"
#include "GameState.h"
#include "Camera.h"

#include <iostream>

/** Internal Definitions */

#define	WINDOW_WIDTH         (1024) // initial width of the window               //
#define	WINDOW_HEIGHT         (768) // initial height of the window               //
#define	WINDOW_POS_X        (100) // initial X position of the window         //
#define	WINDOW_POS_Y        (100) // initial Y position of the window         //

#define RC_OK                 (0) // Everything went ok                       //
#define RC_INVALID_ARGUMENTS  (1) // Invalid arguments given to the program   //
#define RC_INPUT_ERROR        (2) // Invalid input to the program             //

#define	ARGUMENTS_PROGRAM     (0) // program name position on argv            //
#define	ARGUMENTS_INPUTFILE   (1) // given input file position on argv        //
#define	ARGUMENTS_REQUIRED    (2) // number of required arguments             //

/** Key definitions */

#define KEY_ESC            ('\e') // Key used to terminate the program - ESC  //
#define KEY_RESET          ('r')
#define KEY_FULLSCREEN     ('f')

/** display callback */
void display(void);

/** window reshape callback  */
void windowResize(int width, int height);

/** keyboardDown callback  */
void keyboardDown(unsigned char key, int x, int y);

/** keyboardUp callback  */
void keyboardUp(unsigned char key, int x, int y);

/** mouse click callback */
void mouse(int button, int state, int x, int y) ;

/** mouse dragging callback  */
void motion(int x, int y) ;

// Game-related objects
World *_world;

/** main function */
int main(int argc, char* argv[])
{
    std::cout << "Starting ex4..." << std::endl;

    // Initialize GLUT
    glutInit(&argc, argv) ;
#ifdef __APPLE__
    glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGBA | GLUT_DEPTH | GLUT_3_2_CORE_PROFILE) ;
#else
    glutInitContextVersion(3, 3);
    glutInitContextFlags(GLUT_FORWARD_COMPATIBLE | GLUT_DEBUG);
    glutInitContextProfile(GLUT_CORE_PROFILE);
    glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGBA | GLUT_DEPTH);
#endif
    glutInitWindowSize(WINDOW_WIDTH, WINDOW_HEIGHT);
    glutInitWindowPosition(WINDOW_POS_X, WINDOW_POS_Y);
    glutCreateWindow("CGP Ex 3");

    // Initialize GLEW
    glewExperimental = GL_TRUE;
    int glewStatus = glewInit();
    if (glewStatus != GLEW_OK) {
        std::cerr << "Unable to initialize GLEW ... exiting" << std::endl;
        exit(1);
    }

    // GLEW has a "bug" where it sets a glError. According to the wiki this
    // can be safely ignored, so we clear the error here:
    glGetError();

#ifdef __APPLE__
    GLint sync = 1;
    CGLSetParameter(CGLGetCurrentContext(), kCGLCPSwapInterval, &sync);
#endif

    // Enable opengl drawing features
    glEnable(GL_DEPTH_TEST);
    glDepthFunc(GL_LEQUAL);
    glEnable(GL_BLEND);
    glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);

    // Set callback functions:
    glutDisplayFunc(display) ;
    glutReshapeFunc(windowResize) ;
    glutKeyboardFunc(keyboardDown);
    glutKeyboardUpFunc(keyboardUp);
    glutMouseFunc(mouse);
    glutMotionFunc(motion);
    glutPassiveMotionFunc(motion);

    glutSetCursor(GLUT_CURSOR_NONE);

    // Initialize ALUT (& background music)
    alutInit(&argc, argv);

    // Initialize random seed
    srand(time(NULL));

    // Set up game
    _world = new World();

    // Set clear color to black:
    glClearColor(0.0f, 0.0f, 0.0f, 1.0f);

    // Start events/drawing loop
    glutMainLoop();

    return 0;
}

// Time
int oldTimeSinceStart = 0;
float physicsTimeStep = 1.0f / 50.0f;
float accumulator = 0.0f;

// FPS
int frames = 0;
int fpsCounter = 0;

void display(void)
{
    // Update the delta
    int timeSinceStart = glutGet(GLUT_ELAPSED_TIME);
    int deltaTime = timeSinceStart - oldTimeSinceStart;
    oldTimeSinceStart = timeSinceStart;

    float dt = (float)deltaTime / 1000.0f;
    if (dt > 0.25f) {
        dt = 0.25f;
    }

    if (GameState::Instance().gameStarted) {
        // We fix the physics timestep based on the information in the following
        // article: http://gafferongames.com/game-physics/fix-your-timestep/
        accumulator += dt;
        while (accumulator >= physicsTimeStep) {
    //        std::cout << "physics update" << std::endl;
            _world->recursiveFixedUpdate(physicsTimeStep);
            accumulator -= physicsTimeStep;
        }
    }

    const double physicsInterpolation = accumulator / physicsTimeStep;

    // Update the game state
    _world->recursiveUpdate(dt);

    // Drawing time

    // Clear the screen buffer
    glClearColor(0.15f, 0.0f, 0.2f, 1.0f);
    glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT);

    // Tell the world to draw itself
    _world->recursiveRender();

    // Print fps
    frames++;
    fpsCounter += deltaTime;
    if (fpsCounter > 1000) {
        std::cout << (frames * 1000) / fpsCounter << " FPS" << std::endl;
        fpsCounter = fpsCounter - 1000;
        frames = 0;
    }

    // Swap those buffers so someone will actually see the results... //
    glutSwapBuffers();

    // Refresh the display
    glutPostRedisplay();
}

// This method is called when the window is resized
int _screenWidth, _screenHeight;
void windowResize(int w, int h)
{
    _screenWidth = w;
    _screenHeight = h;

    // set the new viewport //
    glViewport(0, 0, w, h);

    // set the perspective of the camera
    Camera::MainCamera()->resize(w, h);

    // Refresh the display //
    glutPostRedisplay();
}

void toggleFullscreen()
{
    static bool fullscreen = false;
    static int previousWidth, previousHeight;
    static int previousX, previousY;

    if (!fullscreen) {
        previousWidth = _screenWidth;
        previousHeight = _screenHeight;
        previousX = glutGet(GLUT_WINDOW_X);
        previousY = glutGet(GLUT_WINDOW_Y);

        glutFullScreen();

        fullscreen = true;
    } else {
        glutReshapeWindow(previousWidth, previousHeight);
        glutPositionWindow(previousX, previousY);

        fullscreen = false;
    }
}

/********************************************************************
 * Function  :	keyboard
 * Arguments :	key : the key that was pressed
 *              x   : x value of the current mouse location
 *              y   : y value of the current mouse location
 * Returns   : n/a
 * Throws    : n/a
 *
 * Purpose   : This function handles all the keyboard input from the user.
 *             It supports terminating the application when the KEY_QUIT is pressed.
 *
 \******************************************************************/
void keyboardDown(unsigned char key, int x, int y)
{
    unsigned int lower_key = tolower(key);

    if (lower_key == KEY_ESC)
    {
        exit(RC_OK);
    }
    else if (lower_key == KEY_RESET)
    {
        delete _world;
        _world = new World;
        Camera::MainCamera()->resize(_screenWidth, _screenHeight);
    }
    else if (lower_key == KEY_FULLSCREEN)
    {
        toggleFullscreen();
    }

    InputManager::Instance().handleKeyDown(lower_key, x, y);
}

/********************************************************************
 * Function  :	keyboardUp
 * Arguments :	key : the key that was relased
 *              x   : x value of the current mouse location
 *              y   : y value of the current mouse location
 * Returns   : n/a
 * Throws    : n/a
 *
 * Purpose   : This function handles all the keyboard input from the user.
 *             It supports terminating the application when the KEY_QUIT is pressed.
 *
 \******************************************************************/
void keyboardUp(unsigned char key, int x, int y)
{
    unsigned int lower_key = tolower(key);

    InputManager::Instance().handleKeyUp(lower_key, x, y);
}

/********************************************************************
 * Function  :   mouse
 * Arguments :   button  : the button that was engaged in some action
 *               state   : the new state of that button
 *               x       : x value of the current mouse location
 *               y       : y value of the current mouse location
 * Returns   :   n/a
 * Throws    :   n/a
 *
 * Purpose   :   This function handles mouse actions.
 *
 \******************************************************************/
void mouse(int button, int state, int x, int y)
{
    if(button == GLUT_LEFT_BUTTON)
    {

    }
    else if (button == GLUT_RIGHT_BUTTON)
    {

    }

    return;
}

/********************************************************************
 * Function  :   motion
 * Arguments :   x   : x value of the current mouse location
 *               y   : y value of the current mouse location
 * Returns   :   n/a
 * Throws    :   n/a
 *
 * Purpose   :   This function handles mouse dragging events.
 *
 \******************************************************************/
void motion(int x, int y)
{
    float oglX = x / _screenWidth;
    float oglY = y / _screenHeight;

    oglX = oglX * 2.0f - 1.0f;
    oglY = oglY * -2.0f + 1.0f;

    InputManager::Instance().handleMouseMove(oglX, oglY);
}
<|endoftext|>


<commit_before>/*
 * Accounts model item, represents an account in the contactlist tree
 * This file is based on TelepathyQtYell Models
 *
 * Copyright (C) 2010 Collabora Ltd. <info@collabora.co.uk>
 * Copyright (C) 2011 Martin Klapetek <martin dot klapetek at gmail dot com>
 *
 * This library 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.1 of the License, or (at your option) any later version.
 *
 * This library 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 library; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
 */

#include "accounts-model-item.h"

#include <TelepathyQt/Account>
#include <TelepathyQt/ContactManager>

#include "accounts-model.h"
#include "contact-model-item.h"

struct AccountsModelItem::Private
{
    Private(const Tp::AccountPtr &account)
        : mAccount(account),
          mOnlineCount(0)
    {
    }

    void setStatus(const QString &value);
    void setStatusMessage(const QString &value);

    Tp::AccountPtr mAccount;
    int mOnlineCount;
};

void AccountsModelItem::Private::setStatus(const QString &value)
{
    Tp::Presence presence = mAccount->currentPresence().barePresence();
    presence.setStatus(Tp::ConnectionPresenceTypeUnset, value, QString());
    mAccount->setRequestedPresence(presence);
}

void AccountsModelItem::Private::setStatusMessage(const QString &value)
{
    Tp::Presence presence = mAccount->currentPresence().barePresence();
    presence.setStatus(Tp::ConnectionPresenceTypeUnset, QString(), value);
    mAccount->setRequestedPresence(presence);
}

AccountsModelItem::AccountsModelItem(const Tp::AccountPtr &account)
    : mPriv(new Private(account))
{
    if (!mPriv->mAccount->connection().isNull()) {
        QTimer::singleShot(0, this, SLOT(onNewConnection()));
    }

    connect(mPriv->mAccount.data(),
            SIGNAL(removed()),
            SLOT(onRemoved()));
    connect(mPriv->mAccount.data(),
            SIGNAL(serviceNameChanged(QString)),
            SLOT(onChanged()));
    connect(mPriv->mAccount.data(),
            SIGNAL(profileChanged(Tp::ProfilePtr)),
            SLOT(onChanged()));
    connect(mPriv->mAccount.data(),
            SIGNAL(iconNameChanged(QString)),
            SLOT(onChanged()));
    connect(mPriv->mAccount.data(),
            SIGNAL(nicknameChanged(QString)),
            SLOT(onChanged()));
    connect(mPriv->mAccount.data(),
            SIGNAL(normalizedNameChanged(QString)),
            SLOT(onChanged()));
    connect(mPriv->mAccount.data(),
            SIGNAL(validityChanged(bool)),
            SLOT(onChanged()));
    connect(mPriv->mAccount.data(),
            SIGNAL(stateChanged(bool)),
            SLOT(onChanged()));
    connect(mPriv->mAccount.data(),
            SIGNAL(capabilitiesChanged(Tp::ConnectionCapabilities)),
            SLOT(onChanged()));
    connect(mPriv->mAccount.data(),
            SIGNAL(connectsAutomaticallyPropertyChanged(bool)),
            SLOT(onChanged()));
    connect(mPriv->mAccount.data(),
            SIGNAL(parametersChanged(QVariantMap)),
            SLOT(onChanged()));
    connect(mPriv->mAccount.data(),
            SIGNAL(changingPresence(bool)),
            SLOT(onChanged()));
    connect(mPriv->mAccount.data(),
            SIGNAL(automaticPresenceChanged(Tp::Presence)),
            SLOT(onChanged()));
    connect(mPriv->mAccount.data(),
            SIGNAL(currentPresenceChanged(Tp::Presence)),
            SLOT(onChanged()));
    connect(mPriv->mAccount.data(),
            SIGNAL(requestedPresenceChanged(Tp::Presence)),
            SLOT(onChanged()));
    connect(mPriv->mAccount.data(),
            SIGNAL(onlinenessChanged(bool)),
            SLOT(onChanged()));
    connect(mPriv->mAccount.data(),
            SIGNAL(avatarChanged(Tp::Avatar)),
            SLOT(onChanged()));
    connect(mPriv->mAccount.data(),
            SIGNAL(onlinenessChanged(bool)),
            SLOT(onChanged()));
    connect(mPriv->mAccount.data(),
            SIGNAL(connectionStatusChanged(Tp::ConnectionStatus)),
            SLOT(onStatusChanged(Tp::ConnectionStatus)));
    connect(mPriv->mAccount.data(),
            SIGNAL(connectionChanged(Tp::ConnectionPtr)),
            SLOT(onConnectionChanged(Tp::ConnectionPtr)));
}

AccountsModelItem::~AccountsModelItem()
{
    delete mPriv;
}

QVariant AccountsModelItem::data(int role) const
{
    switch (role) {
    case AccountsModel::ItemRole:
        return QVariant::fromValue((AccountsModelItem*)this);
    case AccountsModel::IdRole:
        return mPriv->mAccount->uniqueIdentifier();
    case AccountsModel::AvatarRole:
        return QVariant::fromValue(mPriv->mAccount->avatar());
    case AccountsModel::ValidRole:
        return mPriv->mAccount->isValid();
    case AccountsModel::EnabledRole:
        return mPriv->mAccount->isEnabled();
    case AccountsModel::ConnectionManagerNameRole:
        return mPriv->mAccount->cmName();
    case AccountsModel::ProtocolNameRole:
        return mPriv->mAccount->protocolName();
    case AccountsModel::DisplayNameRole:
    case Qt::DisplayRole:
        return mPriv->mAccount->displayName();
    case AccountsModel::IconRole:
        return mPriv->mAccount->iconName();
    case AccountsModel::NicknameRole:
        return mPriv->mAccount->nickname();
    case AccountsModel::ConnectsAutomaticallyRole:
        return mPriv->mAccount->connectsAutomatically();
    case AccountsModel::ChangingPresenceRole:
        return mPriv->mAccount->isChangingPresence();
    case AccountsModel::AutomaticPresenceRole:
        return mPriv->mAccount->automaticPresence().status();
    case AccountsModel::AutomaticPresenceTypeRole:
        return mPriv->mAccount->automaticPresence().type();
    case AccountsModel::AutomaticPresenceStatusMessageRole:
        return mPriv->mAccount->automaticPresence().statusMessage();
    case AccountsModel::CurrentPresenceRole:
        return mPriv->mAccount->currentPresence().status();
    case AccountsModel::CurrentPresenceTypeRole:
        return mPriv->mAccount->currentPresence().type();
    case AccountsModel::CurrentPresenceStatusMessageRole:
        return mPriv->mAccount->currentPresence().statusMessage();
    case AccountsModel::RequestedPresenceRole:
        return mPriv->mAccount->requestedPresence().status();
    case AccountsModel::RequestedPresenceTypeRole:
        return mPriv->mAccount->requestedPresence().type();
    case AccountsModel::RequestedPresenceStatusMessageRole:
        return mPriv->mAccount->requestedPresence().statusMessage();
    case AccountsModel::ConnectionStatusRole:
        return mPriv->mAccount->connectionStatus();
    case AccountsModel::ConnectionStatusReasonRole:
        return mPriv->mAccount->connectionStatusReason();
    case AccountsModel::TotalUsersCountRole:
        return size();
    case AccountsModel::OnlineUsersCountRole:
        return mPriv->mOnlineCount;
    default:
        return QVariant();
    }
}

bool AccountsModelItem::setData(int role, const QVariant &value)
{
    switch (role) {
    case AccountsModel::EnabledRole:
        setEnabled(value.toBool());
        return true;
    case AccountsModel::RequestedPresenceRole:
        mPriv->setStatus(value.toString());
        return true;
    case AccountsModel::RequestedPresenceStatusMessageRole:
        mPriv->setStatusMessage(value.toString());
        return true;
    case AccountsModel::NicknameRole:
        setNickname(value.toString());
        return true;
    case AccountsModel::AvatarRole:
        mPriv->mAccount->setAvatar(value.value<Tp::Avatar>());
        return true;
    default:
        return false;
    }
}

Tp::AccountPtr AccountsModelItem::account() const
{
    return mPriv->mAccount;
}

void AccountsModelItem::setEnabled(bool value)
{
    mPriv->mAccount->setEnabled(value);
}

void AccountsModelItem::setNickname(const QString &value)
{
    mPriv->mAccount->setNickname(value);
}

void AccountsModelItem::setAutomaticPresence(int type, const QString &status, const QString &statusMessage)
{
    Tp::Presence presence;
    presence.setStatus((Tp::ConnectionPresenceType) type, status, statusMessage);
    mPriv->mAccount->setAutomaticPresence(presence);
}

void AccountsModelItem::setRequestedPresence(int type, const QString &status, const QString &statusMessage)
{
    Tp::Presence presence;
    presence.setStatus((Tp::ConnectionPresenceType) type, status, statusMessage);
    mPriv->mAccount->setRequestedPresence(presence);
}

void AccountsModelItem::onRemoved()
{
    int index = parent()->indexOf(this);
    Q_EMIT childrenRemoved(parent(), index, index);
}

void AccountsModelItem::onChanged()
{
    Q_EMIT changed(this);
}

void AccountsModelItem::onContactsChanged(const Tp::Contacts &addedContacts,
        const Tp::Contacts &removedContacts)
{
    Q_FOREACH (const Tp::ContactPtr &contact, removedContacts) {
        for (int i = 0; i < size(); ++i) {
            ContactModelItem *item = qobject_cast<ContactModelItem *>(childAt(i));
            if (item->contact() == contact) {
                Q_EMIT childrenRemoved(this, i, i);
                break;
            }
        }
    }

    // get the list of contact ids in the children
    QStringList idList;
    int numElems = size();
    for (int i = 0; i < numElems; ++i) {
        ContactModelItem *item = qobject_cast<ContactModelItem *>(childAt(i));
        if (item) {
            idList.append(item->contact()->id());
        }
    }

    QList<TreeNode *> newNodes;
    Q_FOREACH (const Tp::ContactPtr &contact, addedContacts) {
        if (!idList.contains(contact->id())) {
            newNodes.append(new ContactModelItem(contact));
        }
    }
    if (!newNodes.isEmpty()) {
        Q_EMIT childrenAdded(this, newNodes);
    }

    countOnlineContacts();
}

void AccountsModelItem::onStatusChanged(Tp::ConnectionStatus status)
{
    onChanged();

    Q_EMIT connectionStatusChanged(mPriv->mAccount->uniqueIdentifier(), status);
}

void AccountsModelItem::onNewConnection()
{
  onConnectionChanged(mPriv->mAccount->connection());
}

void AccountsModelItem::onConnectionChanged(const Tp::ConnectionPtr &connection)
{
    onChanged();

    // if the connection is invalid or disconnected, clear the contacts list
    if (connection.isNull()
            || !connection->isValid()
            || connection->status() == Tp::ConnectionStatusDisconnected) {
        if (size() > 0) {
            Q_EMIT childrenRemoved(this, 0, size() - 1);
        }
        return;
    }

    Tp::ContactManagerPtr manager = connection->contactManager();

    connect(manager.data(),
            SIGNAL(allKnownContactsChanged(Tp::Contacts,Tp::Contacts,
                                           Tp::Channel::GroupMemberChangeDetails)),
            SLOT(onContactsChanged(Tp::Contacts,Tp::Contacts)));

    connect(manager.data(),
            SIGNAL(stateChanged(Tp::ContactListState)),
            SLOT(onContactManagerStateChanged(Tp::ContactListState)));
    onContactManagerStateChanged(manager->state());
}

void AccountsModelItem::onContactManagerStateChanged(Tp::ContactListState state)
{
    if (state == Tp::ContactListStateSuccess) {
        clearContacts();
        addKnownContacts();
    }
}

void AccountsModelItem::clearContacts()
{
    if (!mPriv->mAccount->connection().isNull() &&
        mPriv->mAccount->connection()->isValid()) {
        Tp::ContactManagerPtr manager = mPriv->mAccount->connection()->contactManager();
        Tp::Contacts contacts = manager->allKnownContacts();

        // remove the items no longer present
        for (int i = 0; i < size(); ++i) {
            bool exists = false;
            ContactModelItem *item = qobject_cast<ContactModelItem *>(childAt(i));
            if (item) {
                Tp::ContactPtr itemContact = item->contact();
                if (contacts.contains(itemContact)) {
                    exists = true;
                }
            }
            if (!exists) {
                Q_EMIT childrenRemoved(this, i, i);
            }
        }
    }
}

void AccountsModelItem::addKnownContacts()
{
    // reload the known contacts if it has a connection
    QList<TreeNode *> newNodes;
    if (!mPriv->mAccount->connection().isNull() &&
        mPriv->mAccount->connection()->isValid()) {
        Tp::ContactManagerPtr manager = mPriv->mAccount->connection()->contactManager();
        Tp::Contacts contacts = manager->allKnownContacts();

        // get the list of contact ids in the children
        QStringList idList;
        int numElems = size();

        for (int i = 0; i < numElems; ++i) {
            ContactModelItem *item = qobject_cast<ContactModelItem *>(childAt(i));
            if (item) {
                idList.append(item->contact()->id());
            }
        }

        // only add the contact item if it is new
        Q_FOREACH (const Tp::ContactPtr &contact, contacts) {
            if (!idList.contains(contact->id())) {
                newNodes.append(new ContactModelItem(contact));
            }
        }
    }

    if (newNodes.count() > 0) {
        Q_EMIT childrenAdded(this, newNodes);
    }

    countOnlineContacts();
}

void AccountsModelItem::countOnlineContacts()
{
    int tmpCounter = 0;
    for (int i = 0; i < size(); ++i) {
        ContactModelItem* contactNode = qobject_cast<ContactModelItem*>(childAt(i));
        Q_ASSERT(contactNode);
        if (contactNode->data(AccountsModel::PresenceTypeRole).toUInt() != Tp::ConnectionPresenceTypeOffline
            && contactNode->data(AccountsModel::PresenceTypeRole).toUInt() != Tp::ConnectionPresenceTypeUnknown) {
            tmpCounter++;
        }
    }

    mPriv->mOnlineCount = tmpCounter;
}

#include "accounts-model-item.moc"
<commit_msg>Add decoration role to accounts model<commit_after>/*
 * Accounts model item, represents an account in the contactlist tree
 * This file is based on TelepathyQtYell Models
 *
 * Copyright (C) 2010 Collabora Ltd. <info@collabora.co.uk>
 * Copyright (C) 2011 Martin Klapetek <martin dot klapetek at gmail dot com>
 *
 * This library 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.1 of the License, or (at your option) any later version.
 *
 * This library 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 library; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
 */

#include "accounts-model-item.h"

#include <TelepathyQt/Account>
#include <TelepathyQt/ContactManager>

#include "accounts-model.h"
#include "contact-model-item.h"

#include <KIcon>

struct AccountsModelItem::Private
{
    Private(const Tp::AccountPtr &account)
        : mAccount(account),
          mOnlineCount(0)
    {
    }

    void setStatus(const QString &value);
    void setStatusMessage(const QString &value);

    Tp::AccountPtr mAccount;
    int mOnlineCount;
};

void AccountsModelItem::Private::setStatus(const QString &value)
{
    Tp::Presence presence = mAccount->currentPresence().barePresence();
    presence.setStatus(Tp::ConnectionPresenceTypeUnset, value, QString());
    mAccount->setRequestedPresence(presence);
}

void AccountsModelItem::Private::setStatusMessage(const QString &value)
{
    Tp::Presence presence = mAccount->currentPresence().barePresence();
    presence.setStatus(Tp::ConnectionPresenceTypeUnset, QString(), value);
    mAccount->setRequestedPresence(presence);
}

AccountsModelItem::AccountsModelItem(const Tp::AccountPtr &account)
    : mPriv(new Private(account))
{
    if (!mPriv->mAccount->connection().isNull()) {
        QTimer::singleShot(0, this, SLOT(onNewConnection()));
    }

    connect(mPriv->mAccount.data(),
            SIGNAL(removed()),
            SLOT(onRemoved()));
    connect(mPriv->mAccount.data(),
            SIGNAL(serviceNameChanged(QString)),
            SLOT(onChanged()));
    connect(mPriv->mAccount.data(),
            SIGNAL(profileChanged(Tp::ProfilePtr)),
            SLOT(onChanged()));
    connect(mPriv->mAccount.data(),
            SIGNAL(iconNameChanged(QString)),
            SLOT(onChanged()));
    connect(mPriv->mAccount.data(),
            SIGNAL(nicknameChanged(QString)),
            SLOT(onChanged()));
    connect(mPriv->mAccount.data(),
            SIGNAL(normalizedNameChanged(QString)),
            SLOT(onChanged()));
    connect(mPriv->mAccount.data(),
            SIGNAL(validityChanged(bool)),
            SLOT(onChanged()));
    connect(mPriv->mAccount.data(),
            SIGNAL(stateChanged(bool)),
            SLOT(onChanged()));
    connect(mPriv->mAccount.data(),
            SIGNAL(capabilitiesChanged(Tp::ConnectionCapabilities)),
            SLOT(onChanged()));
    connect(mPriv->mAccount.data(),
            SIGNAL(connectsAutomaticallyPropertyChanged(bool)),
            SLOT(onChanged()));
    connect(mPriv->mAccount.data(),
            SIGNAL(parametersChanged(QVariantMap)),
            SLOT(onChanged()));
    connect(mPriv->mAccount.data(),
            SIGNAL(changingPresence(bool)),
            SLOT(onChanged()));
    connect(mPriv->mAccount.data(),
            SIGNAL(automaticPresenceChanged(Tp::Presence)),
            SLOT(onChanged()));
    connect(mPriv->mAccount.data(),
            SIGNAL(currentPresenceChanged(Tp::Presence)),
            SLOT(onChanged()));
    connect(mPriv->mAccount.data(),
            SIGNAL(requestedPresenceChanged(Tp::Presence)),
            SLOT(onChanged()));
    connect(mPriv->mAccount.data(),
            SIGNAL(onlinenessChanged(bool)),
            SLOT(onChanged()));
    connect(mPriv->mAccount.data(),
            SIGNAL(avatarChanged(Tp::Avatar)),
            SLOT(onChanged()));
    connect(mPriv->mAccount.data(),
            SIGNAL(onlinenessChanged(bool)),
            SLOT(onChanged()));
    connect(mPriv->mAccount.data(),
            SIGNAL(connectionStatusChanged(Tp::ConnectionStatus)),
            SLOT(onStatusChanged(Tp::ConnectionStatus)));
    connect(mPriv->mAccount.data(),
            SIGNAL(connectionChanged(Tp::ConnectionPtr)),
            SLOT(onConnectionChanged(Tp::ConnectionPtr)));
}

AccountsModelItem::~AccountsModelItem()
{
    delete mPriv;
}

QVariant AccountsModelItem::data(int role) const
{
    switch (role) {
    case AccountsModel::ItemRole:
        return QVariant::fromValue((AccountsModelItem*)this);
    case AccountsModel::IdRole:
        return mPriv->mAccount->uniqueIdentifier();
    case AccountsModel::AvatarRole:
        return QVariant::fromValue(mPriv->mAccount->avatar());
    case AccountsModel::ValidRole:
        return mPriv->mAccount->isValid();
    case AccountsModel::EnabledRole:
        return mPriv->mAccount->isEnabled();
    case AccountsModel::ConnectionManagerNameRole:
        return mPriv->mAccount->cmName();
    case AccountsModel::ProtocolNameRole:
        return mPriv->mAccount->protocolName();
    case AccountsModel::DisplayNameRole:
    case Qt::DisplayRole:
        return mPriv->mAccount->displayName();
    case Qt::DecorationRole:
        return KIcon(mPriv->mAccount->iconName());
    case AccountsModel::IconRole:
        return mPriv->mAccount->iconName();
    case AccountsModel::NicknameRole:
        return mPriv->mAccount->nickname();
    case AccountsModel::ConnectsAutomaticallyRole:
        return mPriv->mAccount->connectsAutomatically();
    case AccountsModel::ChangingPresenceRole:
        return mPriv->mAccount->isChangingPresence();
    case AccountsModel::AutomaticPresenceRole:
        return mPriv->mAccount->automaticPresence().status();
    case AccountsModel::AutomaticPresenceTypeRole:
        return mPriv->mAccount->automaticPresence().type();
    case AccountsModel::AutomaticPresenceStatusMessageRole:
        return mPriv->mAccount->automaticPresence().statusMessage();
    case AccountsModel::CurrentPresenceRole:
        return mPriv->mAccount->currentPresence().status();
    case AccountsModel::CurrentPresenceTypeRole:
        return mPriv->mAccount->currentPresence().type();
    case AccountsModel::CurrentPresenceStatusMessageRole:
        return mPriv->mAccount->currentPresence().statusMessage();
    case AccountsModel::RequestedPresenceRole:
        return mPriv->mAccount->requestedPresence().status();
    case AccountsModel::RequestedPresenceTypeRole:
        return mPriv->mAccount->requestedPresence().type();
    case AccountsModel::RequestedPresenceStatusMessageRole:
        return mPriv->mAccount->requestedPresence().statusMessage();
    case AccountsModel::ConnectionStatusRole:
        return mPriv->mAccount->connectionStatus();
    case AccountsModel::ConnectionStatusReasonRole:
        return mPriv->mAccount->connectionStatusReason();
    case AccountsModel::TotalUsersCountRole:
        return size();
    case AccountsModel::OnlineUsersCountRole:
        return mPriv->mOnlineCount;
    default:
        return QVariant();
    }
}

bool AccountsModelItem::setData(int role, const QVariant &value)
{
    switch (role) {
    case AccountsModel::EnabledRole:
        setEnabled(value.toBool());
        return true;
    case AccountsModel::RequestedPresenceRole:
        mPriv->setStatus(value.toString());
        return true;
    case AccountsModel::RequestedPresenceStatusMessageRole:
        mPriv->setStatusMessage(value.toString());
        return true;
    case AccountsModel::NicknameRole:
        setNickname(value.toString());
        return true;
    case AccountsModel::AvatarRole:
        mPriv->mAccount->setAvatar(value.value<Tp::Avatar>());
        return true;
    default:
        return false;
    }
}

Tp::AccountPtr AccountsModelItem::account() const
{
    return mPriv->mAccount;
}

void AccountsModelItem::setEnabled(bool value)
{
    mPriv->mAccount->setEnabled(value);
}

void AccountsModelItem::setNickname(const QString &value)
{
    mPriv->mAccount->setNickname(value);
}

void AccountsModelItem::setAutomaticPresence(int type, const QString &status, const QString &statusMessage)
{
    Tp::Presence presence;
    presence.setStatus((Tp::ConnectionPresenceType) type, status, statusMessage);
    mPriv->mAccount->setAutomaticPresence(presence);
}

void AccountsModelItem::setRequestedPresence(int type, const QString &status, const QString &statusMessage)
{
    Tp::Presence presence;
    presence.setStatus((Tp::ConnectionPresenceType) type, status, statusMessage);
    mPriv->mAccount->setRequestedPresence(presence);
}

void AccountsModelItem::onRemoved()
{
    int index = parent()->indexOf(this);
    Q_EMIT childrenRemoved(parent(), index, index);
}

void AccountsModelItem::onChanged()
{
    Q_EMIT changed(this);
}

void AccountsModelItem::onContactsChanged(const Tp::Contacts &addedContacts,
        const Tp::Contacts &removedContacts)
{
    Q_FOREACH (const Tp::ContactPtr &contact, removedContacts) {
        for (int i = 0; i < size(); ++i) {
            ContactModelItem *item = qobject_cast<ContactModelItem *>(childAt(i));
            if (item->contact() == contact) {
                Q_EMIT childrenRemoved(this, i, i);
                break;
            }
        }
    }

    // get the list of contact ids in the children
    QStringList idList;
    int numElems = size();
    for (int i = 0; i < numElems; ++i) {
        ContactModelItem *item = qobject_cast<ContactModelItem *>(childAt(i));
        if (item) {
            idList.append(item->contact()->id());
        }
    }

    QList<TreeNode *> newNodes;
    Q_FOREACH (const Tp::ContactPtr &contact, addedContacts) {
        if (!idList.contains(contact->id())) {
            newNodes.append(new ContactModelItem(contact));
        }
    }
    if (!newNodes.isEmpty()) {
        Q_EMIT childrenAdded(this, newNodes);
    }

    countOnlineContacts();
}

void AccountsModelItem::onStatusChanged(Tp::ConnectionStatus status)
{
    onChanged();

    Q_EMIT connectionStatusChanged(mPriv->mAccount->uniqueIdentifier(), status);
}

void AccountsModelItem::onNewConnection()
{
  onConnectionChanged(mPriv->mAccount->connection());
}

void AccountsModelItem::onConnectionChanged(const Tp::ConnectionPtr &connection)
{
    onChanged();

    // if the connection is invalid or disconnected, clear the contacts list
    if (connection.isNull()
            || !connection->isValid()
            || connection->status() == Tp::ConnectionStatusDisconnected) {
        if (size() > 0) {
            Q_EMIT childrenRemoved(this, 0, size() - 1);
        }
        return;
    }

    Tp::ContactManagerPtr manager = connection->contactManager();

    connect(manager.data(),
            SIGNAL(allKnownContactsChanged(Tp::Contacts,Tp::Contacts,
                                           Tp::Channel::GroupMemberChangeDetails)),
            SLOT(onContactsChanged(Tp::Contacts,Tp::Contacts)));

    connect(manager.data(),
            SIGNAL(stateChanged(Tp::ContactListState)),
            SLOT(onContactManagerStateChanged(Tp::ContactListState)));
    onContactManagerStateChanged(manager->state());
}

void AccountsModelItem::onContactManagerStateChanged(Tp::ContactListState state)
{
    if (state == Tp::ContactListStateSuccess) {
        clearContacts();
        addKnownContacts();
    }
}

void AccountsModelItem::clearContacts()
{
    if (!mPriv->mAccount->connection().isNull() &&
        mPriv->mAccount->connection()->isValid()) {
        Tp::ContactManagerPtr manager = mPriv->mAccount->connection()->contactManager();
        Tp::Contacts contacts = manager->allKnownContacts();

        // remove the items no longer present
        for (int i = 0; i < size(); ++i) {
            bool exists = false;
            ContactModelItem *item = qobject_cast<ContactModelItem *>(childAt(i));
            if (item) {
                Tp::ContactPtr itemContact = item->contact();
                if (contacts.contains(itemContact)) {
                    exists = true;
                }
            }
            if (!exists) {
                Q_EMIT childrenRemoved(this, i, i);
            }
        }
    }
}

void AccountsModelItem::addKnownContacts()
{
    // reload the known contacts if it has a connection
    QList<TreeNode *> newNodes;
    if (!mPriv->mAccount->connection().isNull() &&
        mPriv->mAccount->connection()->isValid()) {
        Tp::ContactManagerPtr manager = mPriv->mAccount->connection()->contactManager();
        Tp::Contacts contacts = manager->allKnownContacts();

        // get the list of contact ids in the children
        QStringList idList;
        int numElems = size();

        for (int i = 0; i < numElems; ++i) {
            ContactModelItem *item = qobject_cast<ContactModelItem *>(childAt(i));
            if (item) {
                idList.append(item->contact()->id());
            }
        }

        // only add the contact item if it is new
        Q_FOREACH (const Tp::ContactPtr &contact, contacts) {
            if (!idList.contains(contact->id())) {
                newNodes.append(new ContactModelItem(contact));
            }
        }
    }

    if (newNodes.count() > 0) {
        Q_EMIT childrenAdded(this, newNodes);
    }

    countOnlineContacts();
}

void AccountsModelItem::countOnlineContacts()
{
    int tmpCounter = 0;
    for (int i = 0; i < size(); ++i) {
        ContactModelItem* contactNode = qobject_cast<ContactModelItem*>(childAt(i));
        Q_ASSERT(contactNode);
        if (contactNode->data(AccountsModel::PresenceTypeRole).toUInt() != Tp::ConnectionPresenceTypeOffline
            && contactNode->data(AccountsModel::PresenceTypeRole).toUInt() != Tp::ConnectionPresenceTypeUnknown) {
            tmpCounter++;
        }
    }

    mPriv->mOnlineCount = tmpCounter;
}

#include "accounts-model-item.moc"
<|endoftext|>


<commit_before>#include "FKDTree.h"
#include "KDPoint.h"
#include <chrono>
#include "KDTreeLinkerAlgoT.h"
#include <sstream>
#include <unistd.h>
#include <thread>
typedef struct float4
{
	float x;
	float y;
	float z;
	float w;
} float4;
static void show_usage(std::string name)
{
	std::cerr << "\nUsage: " << name << " <option(s)>" << " Options:\n"
			<< "\t-h,--help\t\tShow this help message\n"
			<< "\t-n <number of points>\tSpecify the number of points to use for the kdtree\n"
			<< "\t-t \tRun the validity tests\n"
			<< "\t-s \tRun the sequential algo\n"
			<< "\t-c \tRun the vanilla cmssw algo\n"
			<< "\t-f \tRun FKDtree algo\n"
			<< "\t-a \tRun all the algos\n"
			<< std::endl;

}
int main(int argc, char* argv[])
{
	if (argc < 3)
	{
		show_usage(argv[0]);
		return 1;
	}

	int nPoints;
	bool runTheTests = false;
	bool runSequential = false;
	bool runFKDTree = false;
	bool runOldKDTree = false;
	for (int i = 1; i < argc; ++i)
	{
		std::string arg = argv[i];
		if ((arg == "-h") || (arg == "--help"))
		{
			show_usage(argv[0]);
			return 0;
		}

		else if (arg == "-n")
		{
			if (i + 1 < argc) // Make sure we aren't at the end of argv!
			{
				i++;
				std::istringstream ss(argv[i]);
				if (!(ss >> nPoints))
					std::cerr << "Invalid number " << argv[i] << '\n';
			}
		}
		else if (arg == "-t")
		{
			runTheTests = true;
		}
		else if (arg == "-s")
		{
			runSequential = true;
		}
		else if (arg == "-f")
		{
			runFKDTree = true;
		}
		else if (arg == "-c")
		{
			runOldKDTree = true;
		}
		else if (arg == "-a")
		{
			runOldKDTree = true;
			runFKDTree = true;
			runSequential = true;
		}
	}

	std::vector<KDPoint<float, 3> > points;
	std::vector<KDPoint<float, 3> > minPoints;
	std::vector<KDPoint<float, 3> > maxPoints;

	float range_x = 1;
	float range_y = 2;
	float range_z = 1;

	KDPoint<float, 3> minPoint(0, 1, 8);
	KDPoint<float, 3> maxPoint(1, 2, 8.3);
	for (int i = 0; i < nPoints; ++i)
	{
		float x = static_cast<float>(rand())
				/ (static_cast<float>(RAND_MAX / 10.1));
		;
		float y = static_cast<float>(rand())
				/ (static_cast<float>(RAND_MAX / 10.1));
		;
		float z = static_cast<float>(rand())
				/ (static_cast<float>(RAND_MAX / 10.1));
		KDPoint<float, 3> Point(x, y, z);
		Point.setId(i);

		points.push_back(Point);
		KDPoint<float, 3> m(x - range_x, y - range_y, z - range_z);
		minPoints.push_back(m);
		KDPoint<float, 3> M(x + range_x, y + range_y, z + range_z);
		maxPoints.push_back(M);

	}

	std::cout << "Cloud of points generated.\n" << std::endl;
	std::this_thread::sleep_for(std::chrono::seconds(1));

	if (runFKDTree)
	{
		long int pointsFound=0;
		std::cout << "FKDTree run will start in 1 second.\n" << std::endl;
		std::this_thread::sleep_for(std::chrono::seconds(1));

		std::chrono::steady_clock::time_point start_building =
				std::chrono::steady_clock::now();
		FKDTree<float, 3> kdtree(nPoints, points);

		kdtree.build();
		std::chrono::steady_clock::time_point end_building =
				std::chrono::steady_clock::now();
		std::cout << "building kdtree with " << nPoints << " points took "
				<< std::chrono::duration_cast < std::chrono::milliseconds
				> (end_building - start_building).count() << "ms" << std::endl;
		if (runTheTests)
		{
			if (kdtree.test_correct_build())
				std::cout << "KDTree built correctly" << std::endl;
			else
				std::cerr << "KDTree wrong" << std::endl;
		}

		std::chrono::steady_clock::time_point start_searching =
				std::chrono::steady_clock::now();
		for (int i = 0; i < nPoints; ++i)
			pointsFound+=kdtree.search_in_the_box(minPoints[i], maxPoints[i]).size();
		std::chrono::steady_clock::time_point end_searching =
				std::chrono::steady_clock::now();

		std::cout << "searching points using kdtree took "
				<< std::chrono::duration_cast < std::chrono::milliseconds
				> (end_searching - start_searching).count()<< "ms\n"
				<< " found points: " << pointsFound<< "\n******************************\n"
						<< std::endl;
	}
//	int pointsFoundNaive = 0;
//
	if (runSequential)
	{
		std::cout << "Sequential run will start in 1 second.\n" << std::endl;
		std::this_thread::sleep_for(std::chrono::seconds(1));
		std::chrono::steady_clock::time_point start_sequential =
				std::chrono::steady_clock::now();
		long int pointsFound = 0;
		for (int i = 0; i < nPoints; ++i)
		{
			for (auto p : points)
			{

				bool inTheBox = true;

				for (int d = 0; d < 3; ++d)
				{

					inTheBox &= (p[d] <= maxPoints[i][d]
							&& p[d] >= minPoints[i][d]);

				}
				pointsFound += inTheBox;
			}

		}

		std::chrono::steady_clock::time_point end_sequential =
				std::chrono::steady_clock::now();
		std::cout << "Sequential search algorithm took "
				<< std::chrono::duration_cast < std::chrono::milliseconds
				> (end_sequential - start_sequential).count() << "ms\n"
				<< " found points: " << pointsFound<< "\n******************************\n" << std::endl;
	}

	if (runOldKDTree)
	{

		float4* cmssw_points;
		cmssw_points = new float4[nPoints];
		for (int j = 0; j < nPoints; j++)
		{
			cmssw_points[j].x = points[j][0];
			cmssw_points[j].y = points[j][1];
			cmssw_points[j].z = points[j][2];
			cmssw_points[j].w = j; //Use this to save the index

		}
		std::cout << "Vanilla CMSSW KDTree run will start in 1 second.\n"
				<< std::endl;
		std::this_thread::sleep_for(std::chrono::seconds(1));
		std::chrono::steady_clock::time_point start_building =
				std::chrono::steady_clock::now();

		KDTreeLinkerAlgo<unsigned, 3> vanilla_tree;
		std::vector<KDTreeNodeInfoT<unsigned, 3> > vanilla_nodes;
		std::vector<KDTreeNodeInfoT<unsigned, 3> > vanilla_founds;

		std::array<float, 3> minpos
		{
		{ 0.0f, 0.0f, 0.0f } }, maxpos
		{
		{ 0.0f, 0.0f, 0.0f } };

		vanilla_tree.clear();
		vanilla_founds.clear();
		for (unsigned i = 0; i < nPoints; ++i)
		{
			float4 pos = cmssw_points[i];
			vanilla_nodes.emplace_back(i, (float) pos.x, (float) pos.y,
					(float) pos.z);
			if (i == 0)
			{
				minpos[0] = pos.x;
				minpos[1] = pos.y;
				minpos[2] = pos.z;
				maxpos[0] = pos.x;
				maxpos[1] = pos.y;
				maxpos[2] = pos.z;
			}
			else
			{
				minpos[0] = std::min((float) pos.x, minpos[0]);
				minpos[1] = std::min((float) pos.y, minpos[1]);
				minpos[2] = std::min((float) pos.z, minpos[2]);
				maxpos[0] = std::max((float) pos.x, maxpos[0]);
				maxpos[1] = std::max((float) pos.y, maxpos[1]);
				maxpos[2] = std::max((float) pos.z, maxpos[2]);
			}
		}

		KDTreeCube cluster_bounds = KDTreeCube(minpos[0], maxpos[0], minpos[1],
				maxpos[1], minpos[2], maxpos[2]);

		vanilla_tree.build(vanilla_nodes, cluster_bounds);
		std::chrono::steady_clock::time_point end_building =
				std::chrono::steady_clock::now();
		long int pointsFound = 0;
		std::chrono::steady_clock::time_point start_searching =
				std::chrono::steady_clock::now();
		for (int i = 0; i < nPoints; ++i)
		{
			KDTreeCube kd_searchcube(minPoints[i][0], maxPoints[i][0],
					minPoints[i][1], maxPoints[i][1], minPoints[i][2],
					maxPoints[i][2]);
			vanilla_tree.search(kd_searchcube, vanilla_founds);
			pointsFound += vanilla_founds.size();
			vanilla_founds.clear();
		}
		std::chrono::steady_clock::time_point end_searching =
				std::chrono::steady_clock::now();

		std::cout << "building cmssw kdtree with " << nPoints << " points took "
				<< std::chrono::duration_cast < std::chrono::milliseconds
				> (end_building - start_building).count() << "ms" << std::endl;
		std::cout << "searching points using cmssw kdtree took "
				<< std::chrono::duration_cast < std::chrono::milliseconds
				> (end_searching - start_searching).count() << "ms"
						<< std::endl;
		std::cout << pointsFound << " points found cmssw in "
				<< std::chrono::duration_cast < std::chrono::milliseconds
				> (end_searching - start_searching).count() << "ms\n"
				<< " found points: " << pointsFound<< "\n******************************\n"

						<< std::endl;

		delete[] cmssw_points;
	}
	return 0;
}
<commit_msg>small adjustments<commit_after>#include "FKDTree.h"
#include "KDPoint.h"
#include <chrono>
#include "KDTreeLinkerAlgoT.h"
#include <sstream>
#include <unistd.h>
#include <thread>
typedef struct float4
{
	float x;
	float y;
	float z;
	float w;
} float4;
static void show_usage(std::string name)
{
	std::cerr << "\nUsage: " << name << " <option(s)>" << " Options:\n"
			<< "\t-h,--help\t\tShow this help message\n"
			<< "\t-n <number of points>\tSpecify the number of points to use for the kdtree\n"
			<< "\t-t \tRun the validity tests\n"
			<< "\t-s \tRun the sequential algo\n"
			<< "\t-c \tRun the vanilla cmssw algo\n"
			<< "\t-f \tRun FKDtree algo\n"
			<< "\t-a \tRun all the algos\n"
			<< std::endl;

}
int main(int argc, char* argv[])
{
	if (argc < 3)
	{
		show_usage(argv[0]);
		return 1;
	}

	int nPoints=100000;
	bool runTheTests = false;
	bool runSequential = false;
	bool runFKDTree = false;
	bool runOldKDTree = false;
	for (int i = 1; i < argc; ++i)
	{
		std::string arg = argv[i];
		if ((arg == "-h") || (arg == "--help"))
		{
			show_usage(argv[0]);
			return 0;
		}

		else if (arg == "-n")
		{
			if (i + 1 < argc) // Make sure we aren't at the end of argv!
			{
				i++;
				std::istringstream ss(argv[i]);
				if (!(ss >> nPoints))
					std::cerr << "Invalid number " << argv[i] << '\n';
			}
		}
		else if (arg == "-t")
		{
			runTheTests = true;
		}
		else if (arg == "-s")
		{
			runSequential = true;
		}
		else if (arg == "-f")
		{
			runFKDTree = true;
		}
		else if (arg == "-c")
		{
			runOldKDTree = true;
		}
		else if (arg == "-a")
		{
			runOldKDTree = true;
			runFKDTree = true;
			runSequential = true;
		}
	}

	std::vector<KDPoint<float, 3> > points;
	std::vector<KDPoint<float, 3> > minPoints;
	std::vector<KDPoint<float, 3> > maxPoints;

	float range_x = 1;
	float range_y = 2;
	float range_z = 1;

	KDPoint<float, 3> minPoint(0, 1, 8);
	KDPoint<float, 3> maxPoint(1, 2, 8.3);
	for (int i = 0; i < nPoints; ++i)
	{
		float x = static_cast<float>(rand())
				/ (static_cast<float>(RAND_MAX / 10.1));
		;
		float y = static_cast<float>(rand())
				/ (static_cast<float>(RAND_MAX / 10.1));
		;
		float z = static_cast<float>(rand())
				/ (static_cast<float>(RAND_MAX / 10.1));
		KDPoint<float, 3> Point(x, y, z);
		Point.setId(i);

		points.push_back(Point);
		KDPoint<float, 3> m(x - range_x, y - range_y, z - range_z);
		minPoints.push_back(m);
		KDPoint<float, 3> M(x + range_x, y + range_y, z + range_z);
		maxPoints.push_back(M);

	}
//needed by the vanilla algo
	float4* cmssw_points;
	cmssw_points = new float4[nPoints];
	for (int j = 0; j < nPoints; j++)
	{
		cmssw_points[j].x = points[j][0];
		cmssw_points[j].y = points[j][1];
		cmssw_points[j].z = points[j][2];
		cmssw_points[j].w = j; //Use this to save the index

	}

	std::cout << "Cloud of points generated.\n" << std::endl;
	std::this_thread::sleep_for(std::chrono::seconds(1));

	if (runFKDTree)
	{
		long int pointsFound=0;
		std::cout << "FKDTree run will start in 1 second.\n" << std::endl;
		std::this_thread::sleep_for(std::chrono::seconds(1));

		std::chrono::steady_clock::time_point start_building =
				std::chrono::steady_clock::now();
		FKDTree<float, 3> kdtree(nPoints, points);

		kdtree.build();
		std::chrono::steady_clock::time_point end_building =
				std::chrono::steady_clock::now();
		std::cout << "building FKDTree with " << nPoints << " points took "
				<< std::chrono::duration_cast < std::chrono::milliseconds
				> (end_building - start_building).count() << "ms" << std::endl;
		if (runTheTests)
		{
			if (kdtree.test_correct_build())
				std::cout << "FKDTree built correctly" << std::endl;
			else
				std::cerr << "FKDTree wrong" << std::endl;
		}

		std::chrono::steady_clock::time_point start_searching =
				std::chrono::steady_clock::now();
		for (int i = 0; i < nPoints; ++i)
			pointsFound+=kdtree.search_in_the_box(minPoints[i], maxPoints[i]).size();
		std::chrono::steady_clock::time_point end_searching =
				std::chrono::steady_clock::now();

		std::cout << "searching points using FKDTree took "
				<< std::chrono::duration_cast < std::chrono::milliseconds
				> (end_searching - start_searching).count()<< "ms\n"
				<< " found points: " << pointsFound<< "\n******************************\n"
						<< std::endl;
	}
//	int pointsFoundNaive = 0;
//
	if (runSequential)
	{
		std::cout << "Sequential run will start in 1 second.\n" << std::endl;
		std::this_thread::sleep_for(std::chrono::seconds(1));
		std::chrono::steady_clock::time_point start_sequential =
				std::chrono::steady_clock::now();
		long int pointsFound = 0;
		for (int i = 0; i < nPoints; ++i)
		{
			for (auto p : points)
			{

				bool inTheBox = true;

				for (int d = 0; d < 3; ++d)
				{

					inTheBox &= (p[d] <= maxPoints[i][d]
							&& p[d] >= minPoints[i][d]);

				}
				pointsFound += inTheBox;
			}

		}

		std::chrono::steady_clock::time_point end_sequential =
				std::chrono::steady_clock::now();
		std::cout << "Sequential search algorithm took "
				<< std::chrono::duration_cast < std::chrono::milliseconds
				> (end_sequential - start_sequential).count() << "ms\n"
				<< " found points: " << pointsFound<< "\n******************************\n" << std::endl;
	}

	if (runOldKDTree)
	{

		std::cout << "Vanilla CMSSW KDTree run will start in 1 second.\n"
				<< std::endl;
		std::this_thread::sleep_for(std::chrono::seconds(1));
		std::chrono::steady_clock::time_point start_building =
				std::chrono::steady_clock::now();

		KDTreeLinkerAlgo<unsigned, 3> vanilla_tree;
		std::vector<KDTreeNodeInfoT<unsigned, 3> > vanilla_nodes;
		std::vector<KDTreeNodeInfoT<unsigned, 3> > vanilla_founds;

		std::array<float, 3> minpos
		{
		{ 0.0f, 0.0f, 0.0f } }, maxpos
		{
		{ 0.0f, 0.0f, 0.0f } };

		vanilla_tree.clear();
		vanilla_founds.clear();
		for (unsigned i = 0; i < nPoints; ++i)
		{
			float4 pos = cmssw_points[i];
			vanilla_nodes.emplace_back(i, (float) pos.x, (float) pos.y,
					(float) pos.z);
			if (i == 0)
			{
				minpos[0] = pos.x;
				minpos[1] = pos.y;
				minpos[2] = pos.z;
				maxpos[0] = pos.x;
				maxpos[1] = pos.y;
				maxpos[2] = pos.z;
			}
			else
			{
				minpos[0] = std::min((float) pos.x, minpos[0]);
				minpos[1] = std::min((float) pos.y, minpos[1]);
				minpos[2] = std::min((float) pos.z, minpos[2]);
				maxpos[0] = std::max((float) pos.x, maxpos[0]);
				maxpos[1] = std::max((float) pos.y, maxpos[1]);
				maxpos[2] = std::max((float) pos.z, maxpos[2]);
			}
		}

		KDTreeCube cluster_bounds = KDTreeCube(minpos[0], maxpos[0], minpos[1],
				maxpos[1], minpos[2], maxpos[2]);

		vanilla_tree.build(vanilla_nodes, cluster_bounds);
		std::chrono::steady_clock::time_point end_building =
				std::chrono::steady_clock::now();
		long int pointsFound = 0;
		std::chrono::steady_clock::time_point start_searching =
				std::chrono::steady_clock::now();
		for (int i = 0; i < nPoints; ++i)
		{
			KDTreeCube kd_searchcube(minPoints[i][0], maxPoints[i][0],
					minPoints[i][1], maxPoints[i][1], minPoints[i][2],
					maxPoints[i][2]);
			vanilla_tree.search(kd_searchcube, vanilla_founds);
			pointsFound += vanilla_founds.size();
			vanilla_founds.clear();
		}
		std::chrono::steady_clock::time_point end_searching =
				std::chrono::steady_clock::now();

		std::cout << "building Vanilla CMSSW KDTree with " << nPoints << " points took "
				<< std::chrono::duration_cast < std::chrono::milliseconds
				> (end_building - start_building).count() << "ms" << std::endl;
		std::cout << "searching points using Vanilla CMSSW KDTree took "
				<< std::chrono::duration_cast < std::chrono::milliseconds
				> (end_searching - start_searching).count() << "ms"
						<< std::endl;
		std::cout << pointsFound << " points found using Vanilla CMSSW KDTree in "
				<< std::chrono::duration_cast < std::chrono::milliseconds
				> (end_searching - start_searching).count() << "ms\n"
				<< " found points: " << pointsFound<< "\n******************************\n"

						<< std::endl;

		delete[] cmssw_points;
	}
	return 0;
}
<|endoftext|>