// Text.cpp: implementation of the CText class.
//
//////////////////////////////////////////////////////////////////////

#include "stdafx.h"
#include "Text.h"

//////////////////////////////////////////////////////////////////////
// Construction/Destruction
//////////////////////////////////////////////////////////////////////

CText::CText(IDirectDraw7 *pdd, IDirectDrawSurface7 *pds, int w, int h)
    : m_pts(NULL)
    , m_Width(w)
    , m_Height(h)
    , m_IsInitialized(false)
{
    // The third COM rule says we should call AddRef on 
    // interface AFTER we made such an assignment.
    //
    if (pdd && pds)
    {
        m_pdd = pdd; m_pdd->AddRef();
        m_pbs = pds; m_pbs->AddRef();
    }
    else
        ATLTRACE(_T("Invalid pointer(s) in CText() constructor.\n"));
}

CText::~CText()
{
    RELEASE(m_pbs);
    RELEASE(m_pdd);
}

// @STEP: #1 Initialize object after creation
HRESULT CText::Initialize()
{
    if (m_IsInitialized)
        return S_FALSE;

    DDSURFACEDESC2 ddsd;

    ddsd.dwSize = sizeof(ddsd);
    ddsd.dwFlags = DDSD_CAPS|DDSD_HEIGHT|DDSD_WIDTH;
    ddsd.ddsCaps.dwCaps = DDSCAPS_OFFSCREENPLAIN|DDSCAPS_SYSTEMMEMORY;
    ddsd.dwWidth  = m_Width;
    ddsd.dwHeight = m_Height;

    if (FAILED(m_pdd->CreateSurface(&ddsd, &m_pts, NULL)))
    {
        ATLTRACE(_T("Text Surface creation failed.\n"));
        return E_FAIL;
    }

    m_Rect.SetRectEmpty();
    m_Color = RGB(255,255,240);     // default color
    m_Shade = RGB(0,0,0);           // no shade

    // set Text Surface key color
    DDCOLORKEY ddck;

    ddck.dwColorSpaceLowValue  = KEY_COLOR;
    ddck.dwColorSpaceHighValue = KEY_COLOR;
    m_pts->SetColorKey(DDCKEY_SRCBLT, &ddck);
    // clear whole Text Surface
    Clear();

    if (m_Font.IsNull())            // create default font
    {
        m_Font.CreateFont(24, 0,0,0, FW_BOLD, 0,0,0
                         , DEFAULT_CHARSET, OUT_TT_PRECIS
                         , CLIP_DEFAULT_PRECIS, NONANTIALIASED_QUALITY
                         , DEFAULT_PITCH, _T("Arial"));
    }
    if (m_Font.IsNull())
        return E_FAIL;

    return S_OK;
}

HRESULT CText::Terminate()
{
    if (!m_IsInitialized)
        return S_FALSE;

    m_Font.DeleteObject();

    RELEASE(m_pts);

    return S_OK;
}

// @STEP: #4 set text. you should not do it for each frame
HRESULT CText::Set(LPCTSTR msg, int x, int y)
{
    CHECK(msg, E_POINTER);

    if (!m_Rect.IsRectEmpty())
    {
        Clear(m_Rect);
    }
    m_Rect.SetRectEmpty();  // a new text is not drawn.

    HDC hdc;
    if (FAILED(m_pts->GetDC(&hdc)))
    {
        ATLTRACE(_T("Cannot get Text Surface DC.\n"));
        return E_FAIL;
    }
    ::SelectObject(hdc, (HFONT)m_Font);
    ::DrawText(hdc, msg, -1, m_Rect, DT_LEFT|DT_CALCRECT);

    ::SetBkMode(hdc, TRANSPARENT);

#if defined(_DRAW_TEXT_SHADOW_)
    // draw shadow if non-black
    if (m_Shade != 0)
    {
        ::SetTextColor(hdc, m_Shade);
        m_Rect.OffsetRect(1,1);
        ::DrawText(hdc, msg, -1, m_Rect, DT_LEFT);
        m_Rect.OffsetRect(-1,-1);
    }
#endif

    ::SetTextColor(hdc, m_Color);
    ::DrawText(hdc, msg, -1, m_Rect, DT_LEFT);

    m_pts->ReleaseDC(hdc);

    // remember screen position
    m_Rect.MoveToXY(x,y);

    return S_OK;
}

// @STEP: #2 set font
HRESULT CText::SetFont(LPCTSTR name, int height, int flag)
{
    int  bold   = flag & FONT_BOLD;
    bool italic = flag & FONT_ITALIC ? true : false;

    if (!m_Font.IsNull())
        m_Font.DeleteObject();

    // select non-antialiased to avoid artifacts
    m_Font.CreateFont(height, 0,0,0, bold, italic,0,0
                     , DEFAULT_CHARSET, OUT_TT_PRECIS
                     , CLIP_DEFAULT_PRECIS, NONANTIALIASED_QUALITY
                     , DEFAULT_PITCH, name);

    if (m_Font.IsNull())
        return E_FAIL;

    return S_OK;
}

// @STEP: #5 draw rendered text each frame
HRESULT CText::Draw()
{
    CRect rc(0, 0, m_Rect.Width(), m_Rect.Height());

    return m_pbs->BltFast(m_Rect.left, m_Rect.top, m_pts, rc, DDBLTFAST_SRCCOLORKEY);
}

// @STEP: #3 set font color
HRESULT CText::SetColor(COLORREF text, COLORREF shadow)
{
    m_Color = text;
    m_Shade = shadow;
    return S_OK;
}

// helper method
HRESULT CText::Clear(void)
{
    CRect rc(0, 0, m_Width, m_Height);
    return Clear(rc);
}

HRESULT CText::Clear(CRect& rc)
{
    rc.MoveToXY(0,0);
    return Clear((LPRECT)rc);
}

HRESULT CText::Clear(LPRECT rc)
{
    DDBLTFX	ddbltfx;
		
	ddbltfx.dwSize = sizeof(ddbltfx);
	ddbltfx.dwFillColor = KEY_COLOR;
	return	m_pts->Blt(rc, NULL, NULL, DDBLT_COLORFILL|DDBLT_WAIT, &ddbltfx);
}
